VirtualBox

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

Last change on this file since 45674 was 45674, checked in by vboxsync, 12 years ago

Main/Machine+Console+Display+VRDEServer,VBoxManage: allow VMs without graphics controller, eliminate annoying spurious error messages about Console not yet powered up when taking screenshots, getting/setting guest properties and updating metrics, make as many parameters to modifyvm as possible case insensitive

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2013 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#include "VRDEServerImpl.h"
19#include "MachineImpl.h"
20#include "VirtualBoxImpl.h"
21#ifdef VBOX_WITH_EXTPACK
22# include "ExtPackManagerImpl.h"
23#endif
24
25#include <iprt/cpp/utils.h>
26#include <iprt/ctype.h>
27#include <iprt/ldr.h>
28#include <iprt/path.h>
29
30#include <VBox/err.h>
31#include <VBox/sup.h>
32
33#include <VBox/RemoteDesktop/VRDE.h>
34
35#include "AutoStateDep.h"
36#include "AutoCaller.h"
37#include "Global.h"
38#include "Logging.h"
39
40// defines
41/////////////////////////////////////////////////////////////////////////////
42#define VRDP_DEFAULT_PORT_STR "3389"
43
44// constructor / destructor
45/////////////////////////////////////////////////////////////////////////////
46
47VRDEServer::VRDEServer()
48 : mParent(NULL)
49{
50}
51
52VRDEServer::~VRDEServer()
53{
54}
55
56HRESULT VRDEServer::FinalConstruct()
57{
58 return BaseFinalConstruct();
59}
60
61void VRDEServer::FinalRelease()
62{
63 uninit();
64 BaseFinalRelease();
65}
66
67// public initializer/uninitializer for internal purposes only
68/////////////////////////////////////////////////////////////////////////////
69
70/**
71 * Initializes the VRDP server object.
72 *
73 * @param aParent Handle of the parent object.
74 */
75HRESULT VRDEServer::init(Machine *aParent)
76{
77 LogFlowThisFunc(("aParent=%p\n", aParent));
78
79 ComAssertRet(aParent, E_INVALIDARG);
80
81 /* Enclose the state transition NotReady->InInit->Ready */
82 AutoInitSpan autoInitSpan(this);
83 AssertReturn(autoInitSpan.isOk(), E_FAIL);
84
85 unconst(mParent) = aParent;
86 /* mPeer is left null */
87
88 mData.allocate();
89
90 mData->mAuthType = AuthType_Null;
91 mData->mAuthTimeout = 0;
92 mData->mAuthLibrary.setNull();
93 mData->mEnabled = FALSE;
94 mData->mAllowMultiConnection = FALSE;
95 mData->mReuseSingleConnection = FALSE;
96 mData->mVrdeExtPack.setNull();
97
98 /* Confirm a successful initialization */
99 autoInitSpan.setSucceeded();
100
101 return S_OK;
102}
103
104/**
105 * Initializes the object given another object
106 * (a kind of copy constructor). This object shares data with
107 * the object passed as an argument.
108 *
109 * @note This object must be destroyed before the original object
110 * it shares data with is destroyed.
111 *
112 * @note Locks @a aThat object for reading.
113 */
114HRESULT VRDEServer::init(Machine *aParent, VRDEServer *aThat)
115{
116 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
117
118 ComAssertRet(aParent && aThat, E_INVALIDARG);
119
120 /* Enclose the state transition NotReady->InInit->Ready */
121 AutoInitSpan autoInitSpan(this);
122 AssertReturn(autoInitSpan.isOk(), E_FAIL);
123
124 unconst(mParent) = aParent;
125 unconst(mPeer) = aThat;
126
127 AutoCaller thatCaller(aThat);
128 AssertComRCReturnRC(thatCaller.rc());
129
130 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
131 mData.share(aThat->mData);
132
133 /* Confirm a successful initialization */
134 autoInitSpan.setSucceeded();
135
136 return S_OK;
137}
138
139/**
140 * Initializes the guest object given another guest object
141 * (a kind of copy constructor). This object makes a private copy of data
142 * of the original object passed as an argument.
143 *
144 * @note Locks @a aThat object for reading.
145 */
146HRESULT VRDEServer::initCopy(Machine *aParent, VRDEServer *aThat)
147{
148 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
149
150 ComAssertRet(aParent && aThat, E_INVALIDARG);
151
152 /* Enclose the state transition NotReady->InInit->Ready */
153 AutoInitSpan autoInitSpan(this);
154 AssertReturn(autoInitSpan.isOk(), E_FAIL);
155
156 unconst(mParent) = aParent;
157 /* mPeer is left null */
158
159 AutoCaller thatCaller(aThat);
160 AssertComRCReturnRC(thatCaller.rc());
161
162 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
163 mData.attachCopy(aThat->mData);
164
165 /* Confirm a successful initialization */
166 autoInitSpan.setSucceeded();
167
168 return S_OK;
169}
170
171/**
172 * Uninitializes the instance and sets the ready flag to FALSE.
173 * Called either from FinalRelease() or by the parent when it gets destroyed.
174 */
175void VRDEServer::uninit()
176{
177 LogFlowThisFunc(("\n"));
178
179 /* Enclose the state transition Ready->InUninit->NotReady */
180 AutoUninitSpan autoUninitSpan(this);
181 if (autoUninitSpan.uninitDone())
182 return;
183
184 mData.free();
185
186 unconst(mPeer) = NULL;
187 unconst(mParent) = NULL;
188}
189
190/**
191 * Loads settings from the given machine node.
192 * May be called once right after this object creation.
193 *
194 * @param aMachineNode <Machine> node.
195 *
196 * @note Locks this object for writing.
197 */
198HRESULT VRDEServer::loadSettings(const settings::VRDESettings &data)
199{
200 using namespace settings;
201
202 AutoCaller autoCaller(this);
203 AssertComRCReturnRC(autoCaller.rc());
204
205 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
206
207 mData->mEnabled = data.fEnabled;
208 mData->mAuthType = data.authType;
209 mData->mAuthTimeout = data.ulAuthTimeout;
210 mData->mAuthLibrary = data.strAuthLibrary;
211 mData->mAllowMultiConnection = data.fAllowMultiConnection;
212 mData->mReuseSingleConnection = data.fReuseSingleConnection;
213 mData->mVrdeExtPack = data.strVrdeExtPack;
214 mData->mProperties = data.mapProperties;
215
216 return S_OK;
217}
218
219/**
220 * Saves settings to the given machine node.
221 *
222 * @param aMachineNode <Machine> node.
223 *
224 * @note Locks this object for reading.
225 */
226HRESULT VRDEServer::saveSettings(settings::VRDESettings &data)
227{
228 AutoCaller autoCaller(this);
229 AssertComRCReturnRC(autoCaller.rc());
230
231 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
232
233 data.fEnabled = !!mData->mEnabled;
234 data.authType = mData->mAuthType;
235 data.strAuthLibrary = mData->mAuthLibrary;
236 data.ulAuthTimeout = mData->mAuthTimeout;
237 data.fAllowMultiConnection = !!mData->mAllowMultiConnection;
238 data.fReuseSingleConnection = !!mData->mReuseSingleConnection;
239 data.strVrdeExtPack = mData->mVrdeExtPack;
240 data.mapProperties = mData->mProperties;
241
242 return S_OK;
243}
244
245// IVRDEServer properties
246/////////////////////////////////////////////////////////////////////////////
247
248STDMETHODIMP VRDEServer::COMGETTER(CheckPrerequisites)(BOOL *aCheckPrerequisites)
249{
250 CheckComArgOutPointerValid(aCheckPrerequisites);
251
252 AutoCaller autoCaller(this);
253 if (FAILED(autoCaller.rc())) return autoCaller.rc();
254
255 BOOL res = TRUE;
256 GraphicsControllerType_T graphicsController = GraphicsControllerType_Null;
257 HRESULT rc = mParent->COMGETTER(GraphicsControllerType)(&graphicsController);
258 if (SUCCEEDED(rc))
259 res &= (graphicsController != GraphicsControllerType_Null);
260 else
261 res = FALSE;
262
263 *aCheckPrerequisites = res;
264
265 return S_OK;
266}
267
268STDMETHODIMP VRDEServer::COMGETTER(Enabled)(BOOL *aEnabled)
269{
270 CheckComArgOutPointerValid(aEnabled);
271
272 AutoCaller autoCaller(this);
273 if (FAILED(autoCaller.rc())) return autoCaller.rc();
274
275 *aEnabled = mData->mEnabled;
276
277 return S_OK;
278}
279
280STDMETHODIMP VRDEServer::COMSETTER(Enabled)(BOOL aEnabled)
281{
282 AutoCaller autoCaller(this);
283 if (FAILED(autoCaller.rc())) return autoCaller.rc();
284
285 /* the machine can also be in saved state for this property to change */
286 AutoMutableOrSavedStateDependency adep(mParent);
287 if (FAILED(adep.rc())) return adep.rc();
288
289 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
290
291 if (mData->mEnabled != aEnabled)
292 {
293 mData.backup();
294 mData->mEnabled = aEnabled;
295
296 /* leave the lock before informing callbacks */
297 alock.release();
298
299 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
300 mParent->setModified(Machine::IsModified_VRDEServer);
301 mlock.release();
302
303 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
304 adep.release();
305
306 mParent->onVRDEServerChange(/* aRestart */ TRUE);
307 }
308
309 return S_OK;
310}
311
312static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
313{
314 /* Gets a string of digits, converts to 16 bit port number.
315 * Note: pszStart <= pszEnd is expected, the string contains
316 * only digits and pszEnd points to the char after last
317 * digit.
318 */
319 int cch = pszEnd - pszStart;
320 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
321 {
322 unsigned uPort = 0;
323 while (pszStart != pszEnd)
324 {
325 uPort = uPort * 10 + *pszStart - '0';
326 pszStart++;
327 }
328
329 if (uPort != 0 && uPort < 0x10000)
330 {
331 if (pu16Port)
332 *pu16Port = (uint16_t)uPort;
333 return VINF_SUCCESS;
334 }
335 }
336
337 return VERR_INVALID_PARAMETER;
338}
339
340static int vrdpServerVerifyPortsString(Bstr ports)
341{
342 com::Utf8Str portRange = ports;
343
344 const char *pszPortRange = portRange.c_str();
345
346 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
347 return VERR_INVALID_PARAMETER;
348
349 /* The string should be like "1000-1010,1020,2000-2003" */
350 while (*pszPortRange)
351 {
352 const char *pszStart = pszPortRange;
353 const char *pszDash = NULL;
354 const char *pszEnd = pszStart;
355
356 while (*pszEnd && *pszEnd != ',')
357 {
358 if (*pszEnd == '-')
359 {
360 if (pszDash != NULL)
361 return VERR_INVALID_PARAMETER; /* More than one '-'. */
362
363 pszDash = pszEnd;
364 }
365 else if (!RT_C_IS_DIGIT(*pszEnd))
366 return VERR_INVALID_PARAMETER;
367
368 pszEnd++;
369 }
370
371 /* Update the next range pointer. */
372 pszPortRange = pszEnd;
373 if (*pszPortRange == ',')
374 {
375 pszPortRange++;
376 }
377
378 /* A probably valid range. Verify and parse it. */
379 int rc;
380 if (pszDash)
381 {
382 rc = portParseNumber(NULL, pszStart, pszDash);
383 if (RT_SUCCESS(rc))
384 rc = portParseNumber(NULL, pszDash + 1, pszEnd);
385 }
386 else
387 rc = portParseNumber(NULL, pszStart, pszEnd);
388
389 if (RT_FAILURE(rc))
390 return rc;
391 }
392
393 return VINF_SUCCESS;
394}
395
396STDMETHODIMP VRDEServer::SetVRDEProperty(IN_BSTR aKey, IN_BSTR aValue)
397{
398 LogFlowThisFunc(("\n"));
399
400 AutoCaller autoCaller(this);
401 if (FAILED(autoCaller.rc())) return autoCaller.rc();
402
403 /* the machine can also be in saved state for this property to change */
404 AutoMutableOrSavedStateDependency adep(mParent);
405 if (FAILED(adep.rc())) return adep.rc();
406
407 Bstr key = aKey;
408
409 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
410
411 /* Special processing for some "standard" properties. */
412 if (key == Bstr("TCP/Ports"))
413 {
414 Bstr ports = aValue;
415
416 /* Verify the string. */
417 int vrc = vrdpServerVerifyPortsString(ports);
418 if (RT_FAILURE(vrc))
419 return E_INVALIDARG;
420
421 if (ports != mData->mProperties["TCP/Ports"])
422 {
423 /* Port value is not verified here because it is up to VRDP transport to
424 * use it. Specifying a wrong port number will cause a running server to
425 * stop. There is no fool proof here.
426 */
427 mData.backup();
428 if (ports == Bstr("0"))
429 mData->mProperties["TCP/Ports"] = VRDP_DEFAULT_PORT_STR;
430 else
431 mData->mProperties["TCP/Ports"] = ports;
432
433 /* leave the lock before informing callbacks */
434 alock.release();
435
436 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
437 mParent->setModified(Machine::IsModified_VRDEServer);
438 mlock.release();
439
440 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
441 adep.release();
442
443 mParent->onVRDEServerChange(/* aRestart */ TRUE);
444 }
445 }
446 else
447 {
448 /* Generic properties processing.
449 * Look up the old value first; if nothing's changed then do nothing.
450 */
451 Utf8Str strValue(aValue);
452 Utf8Str strKey(aKey);
453 Utf8Str strOldValue;
454
455 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
456 if (it != mData->mProperties.end())
457 strOldValue = it->second;
458
459 if (strOldValue != strValue)
460 {
461 if (strValue.isEmpty())
462 mData->mProperties.erase(strKey);
463 else
464 mData->mProperties[strKey] = strValue;
465
466 /* leave the lock before informing callbacks */
467 alock.release();
468
469 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
470 mParent->setModified(Machine::IsModified_VRDEServer);
471 mlock.release();
472
473 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
474 adep.release();
475
476 mParent->onVRDEServerChange(/* aRestart */ TRUE);
477 }
478 }
479
480 return S_OK;
481}
482
483STDMETHODIMP VRDEServer::GetVRDEProperty(IN_BSTR aKey, BSTR *aValue)
484{
485 CheckComArgOutPointerValid(aValue);
486
487 AutoCaller autoCaller(this);
488 if (FAILED(autoCaller.rc())) return autoCaller.rc();
489
490 Bstr key = aKey;
491 Bstr value;
492
493 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
494
495 Utf8Str strKey(key);
496 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
497 if (it != mData->mProperties.end())
498 value = it->second; // source is a Utf8Str
499 else if (strKey == "TCP/Ports")
500 value = VRDP_DEFAULT_PORT_STR;
501 value.cloneTo(aValue);
502
503 return S_OK;
504}
505
506static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
507{
508 int rc = VINF_SUCCESS;
509
510 RTLDRMOD hmod = NIL_RTLDRMOD;
511
512 RTERRINFOSTATIC ErrInfo;
513 RTErrInfoInitStatic(&ErrInfo);
514 if (RTPathHavePath(pszLibraryName))
515 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
516 else
517 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
518 if (RT_SUCCESS(rc))
519 {
520 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
521
522 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
523 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
524 }
525 else
526 {
527 if (RTErrInfoIsSet(&ErrInfo.Core))
528 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
529 else
530 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
531
532 hmod = NIL_RTLDRMOD;
533 }
534
535 if (RT_SUCCESS(rc))
536 {
537 *phmod = hmod;
538 }
539 else
540 {
541 if (hmod != NIL_RTLDRMOD)
542 {
543 RTLdrClose(hmod);
544 hmod = NIL_RTLDRMOD;
545 }
546 }
547
548 return rc;
549}
550
551STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProperties))
552{
553 if (ComSafeArrayOutIsNull(aProperties))
554 return E_POINTER;
555
556 AutoCaller autoCaller(this);
557 if (FAILED(autoCaller.rc())) return autoCaller.rc();
558
559 size_t cProperties = 0;
560
561 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
562 if (!mData->mEnabled)
563 {
564 com::SafeArray<BSTR> properties(cProperties);
565 properties.detachTo(ComSafeArrayOutArg(aProperties));
566 return S_OK;
567 }
568 alock.release();
569
570 /*
571 * Check that a VRDE extension pack name is set and resolve it into a
572 * library path.
573 */
574 Bstr bstrExtPack;
575 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
576 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
577 if (FAILED(hrc))
578 return hrc;
579 if (bstrExtPack.isEmpty())
580 return E_FAIL;
581
582 Utf8Str strExtPack(bstrExtPack);
583 Utf8Str strVrdeLibrary;
584 int vrc = VINF_SUCCESS;
585 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
586 strVrdeLibrary = "VBoxVRDP";
587 else
588 {
589#ifdef VBOX_WITH_EXTPACK
590 VirtualBox *pVirtualBox = mParent->getVirtualBox();
591 ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager();
592 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
593#else
594 vrc = VERR_FILE_NOT_FOUND;
595#endif
596 }
597 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
598
599 if (RT_SUCCESS(vrc))
600 {
601 /*
602 * Load the VRDE library and start the server, if it is enabled.
603 */
604 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
605 RTLDRMOD hmod = NIL_RTLDRMOD;
606 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
607 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
608 if (RT_SUCCESS(vrc))
609 {
610 const char * const *papszNames = pfn();
611
612 if (papszNames)
613 {
614 size_t i;
615 for (i = 0; papszNames[i] != NULL; ++i)
616 {
617 cProperties++;
618 }
619 }
620 Log(("VRDEPROP: %d properties\n", cProperties));
621
622 com::SafeArray<BSTR> properties(cProperties);
623
624 if (cProperties > 0)
625 {
626 size_t i;
627 for (i = 0; papszNames[i] != NULL && i < cProperties; ++i)
628 {
629 Bstr tmp(papszNames[i]);
630 tmp.cloneTo(&properties[i]);
631 }
632 }
633
634 /* Do not forget to unload the library. */
635 RTLdrClose(hmod);
636 hmod = NIL_RTLDRMOD;
637
638 properties.detachTo(ComSafeArrayOutArg(aProperties));
639 }
640 }
641
642 if (RT_FAILURE(vrc))
643 {
644 return E_FAIL;
645 }
646
647 return S_OK;
648}
649
650STDMETHODIMP VRDEServer::COMGETTER(AuthType)(AuthType_T *aType)
651{
652 CheckComArgOutPointerValid(aType);
653
654 AutoCaller autoCaller(this);
655 if (FAILED(autoCaller.rc())) return autoCaller.rc();
656
657 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
658
659 *aType = mData->mAuthType;
660
661 return S_OK;
662}
663
664STDMETHODIMP VRDEServer::COMSETTER(AuthType)(AuthType_T aType)
665{
666 AutoCaller autoCaller(this);
667 if (FAILED(autoCaller.rc())) return autoCaller.rc();
668
669 /* the machine can also be in saved state for this property to change */
670 AutoMutableOrSavedStateDependency adep(mParent);
671 if (FAILED(adep.rc())) return adep.rc();
672
673 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
674
675 if (mData->mAuthType != aType)
676 {
677 mData.backup();
678 mData->mAuthType = aType;
679
680 /* leave the lock before informing callbacks */
681 alock.release();
682
683 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
684 mParent->setModified(Machine::IsModified_VRDEServer);
685 mlock.release();
686
687 mParent->onVRDEServerChange(/* aRestart */ TRUE);
688 }
689
690 return S_OK;
691}
692
693STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout)(ULONG *aTimeout)
694{
695 CheckComArgOutPointerValid(aTimeout);
696
697 AutoCaller autoCaller(this);
698 if (FAILED(autoCaller.rc())) return autoCaller.rc();
699
700 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
701
702 *aTimeout = mData->mAuthTimeout;
703
704 return S_OK;
705}
706
707STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout)(ULONG aTimeout)
708{
709 AutoCaller autoCaller(this);
710 if (FAILED(autoCaller.rc())) return autoCaller.rc();
711
712 /* the machine can also be in saved state for this property to change */
713 AutoMutableOrSavedStateDependency adep(mParent);
714 if (FAILED(adep.rc())) return adep.rc();
715
716 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
717
718 if (aTimeout != mData->mAuthTimeout)
719 {
720 mData.backup();
721 mData->mAuthTimeout = aTimeout;
722
723 /* leave the lock before informing callbacks */
724 alock.release();
725
726 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
727 mParent->setModified(Machine::IsModified_VRDEServer);
728 mlock.release();
729
730 /* sunlover 20060131: This setter does not require the notification
731 * really */
732#if 0
733 mParent->onVRDEServerChange();
734#endif
735 }
736
737 return S_OK;
738}
739
740STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary)(BSTR *aLibrary)
741{
742 CheckComArgOutPointerValid(aLibrary);
743
744 AutoCaller autoCaller(this);
745 if (FAILED(autoCaller.rc())) return autoCaller.rc();
746
747 Bstr bstrLibrary;
748
749 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
750 bstrLibrary = mData->mAuthLibrary;
751 alock.release();
752
753 if (bstrLibrary.isEmpty())
754 {
755 /* Get the global setting. */
756 ComPtr<ISystemProperties> systemProperties;
757 HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
758
759 if (SUCCEEDED(hrc))
760 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());
761
762 if (FAILED(hrc))
763 return setError(hrc, "failed to query the library setting\n");
764 }
765
766 bstrLibrary.cloneTo(aLibrary);
767
768 return S_OK;
769}
770
771STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary)(IN_BSTR aLibrary)
772{
773 AutoCaller autoCaller(this);
774 if (FAILED(autoCaller.rc())) return autoCaller.rc();
775
776 /* the machine can also be in saved state for this property to change */
777 AutoMutableOrSavedStateDependency adep(mParent);
778 if (FAILED(adep.rc())) return adep.rc();
779
780 Bstr bstrLibrary(aLibrary);
781
782 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
783
784 if (mData->mAuthLibrary != bstrLibrary)
785 {
786 mData.backup();
787 mData->mAuthLibrary = bstrLibrary;
788
789 /* leave the lock before informing callbacks */
790 alock.release();
791
792 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
793 mParent->setModified(Machine::IsModified_VRDEServer);
794 mlock.release();
795
796 mParent->onVRDEServerChange(/* aRestart */ TRUE);
797 }
798
799 return S_OK;
800}
801
802STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection)(BOOL *aAllowMultiConnection)
803{
804 CheckComArgOutPointerValid(aAllowMultiConnection);
805
806 AutoCaller autoCaller(this);
807 if (FAILED(autoCaller.rc())) return autoCaller.rc();
808
809 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
810
811 *aAllowMultiConnection = mData->mAllowMultiConnection;
812
813 return S_OK;
814}
815
816STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection)(BOOL aAllowMultiConnection)
817{
818 AutoCaller autoCaller(this);
819 if (FAILED(autoCaller.rc())) return autoCaller.rc();
820
821 /* the machine can also be in saved state for this property to change */
822 AutoMutableOrSavedStateDependency adep(mParent);
823 if (FAILED(adep.rc())) return adep.rc();
824
825 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
826
827 if (mData->mAllowMultiConnection != aAllowMultiConnection)
828 {
829 mData.backup();
830 mData->mAllowMultiConnection = aAllowMultiConnection;
831
832 /* leave the lock before informing callbacks */
833 alock.release();
834
835 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
836 mParent->setModified(Machine::IsModified_VRDEServer);
837 mlock.release();
838
839 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
840 }
841
842 return S_OK;
843}
844
845STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection)(BOOL *aReuseSingleConnection)
846{
847 CheckComArgOutPointerValid(aReuseSingleConnection);
848
849 AutoCaller autoCaller(this);
850 if (FAILED(autoCaller.rc())) return autoCaller.rc();
851
852 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
853
854 *aReuseSingleConnection = mData->mReuseSingleConnection;
855
856 return S_OK;
857}
858
859STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection)(BOOL aReuseSingleConnection)
860{
861 AutoCaller autoCaller(this);
862 if (FAILED(autoCaller.rc())) return autoCaller.rc();
863
864 /* the machine can also be in saved state for this property to change */
865 AutoMutableOrSavedStateDependency adep(mParent);
866 if (FAILED(adep.rc())) return adep.rc();
867
868 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
869
870 if (mData->mReuseSingleConnection != aReuseSingleConnection)
871 {
872 mData.backup();
873 mData->mReuseSingleConnection = aReuseSingleConnection;
874
875 /* leave the lock before informing callbacks */
876 alock.release();
877
878 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
879 mParent->setModified(Machine::IsModified_VRDEServer);
880 mlock.release();
881
882 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo needs a restart?
883 }
884
885 return S_OK;
886}
887
888STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack)(BSTR *aExtPack)
889{
890 CheckComArgOutPointerValid(aExtPack);
891
892 AutoCaller autoCaller(this);
893 HRESULT hrc = autoCaller.rc();
894 if (SUCCEEDED(hrc))
895 {
896 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
897 Utf8Str strExtPack = mData->mVrdeExtPack;
898 alock.release();
899
900 if (strExtPack.isNotEmpty())
901 {
902 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
903 hrc = S_OK;
904 else
905 {
906#ifdef VBOX_WITH_EXTPACK
907 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
908 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
909#else
910 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
911#endif
912 }
913 if (SUCCEEDED(hrc))
914 strExtPack.cloneTo(aExtPack);
915 }
916 else
917 {
918 /* Get the global setting. */
919 ComPtr<ISystemProperties> systemProperties;
920 hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
921 if (SUCCEEDED(hrc))
922 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(aExtPack);
923 }
924 }
925
926 return hrc;
927}
928
929STDMETHODIMP VRDEServer::COMSETTER(VRDEExtPack)(IN_BSTR aExtPack)
930{
931 CheckComArgNotNull(aExtPack);
932 Utf8Str strExtPack(aExtPack);
933
934 AutoCaller autoCaller(this);
935 HRESULT hrc = autoCaller.rc();
936 if (SUCCEEDED(hrc))
937 {
938 /* the machine can also be in saved state for this property to change */
939 AutoMutableOrSavedStateDependency adep(mParent);
940 hrc = adep.rc();
941 if (SUCCEEDED(hrc))
942 {
943 /*
944 * If not empty, check the specific extension pack.
945 */
946 if (!strExtPack.isEmpty())
947 {
948 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
949 hrc = S_OK;
950 else
951 {
952#ifdef VBOX_WITH_EXTPACK
953 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
954 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
955#else
956 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
957#endif
958 }
959 }
960 if (SUCCEEDED(hrc))
961 {
962 /*
963 * Update the setting if there is an actual change, post an
964 * change event to trigger a VRDE server restart.
965 */
966 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
967 if (strExtPack != mData->mVrdeExtPack)
968 {
969 mData.backup();
970 mData->mVrdeExtPack = strExtPack;
971
972 /* leave the lock before informing callbacks */
973 alock.release();
974
975 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
976 mParent->setModified(Machine::IsModified_VRDEServer);
977 mlock.release();
978
979 mParent->onVRDEServerChange(/* aRestart */ TRUE);
980 }
981 }
982 }
983 }
984
985 return hrc;
986}
987
988// public methods only for internal purposes
989/////////////////////////////////////////////////////////////////////////////
990
991/**
992 * @note Locks this object for writing.
993 */
994void VRDEServer::rollback()
995{
996 /* sanity */
997 AutoCaller autoCaller(this);
998 AssertComRCReturnVoid(autoCaller.rc());
999
1000 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1001
1002 mData.rollback();
1003}
1004
1005/**
1006 * @note Locks this object for writing, together with the peer object (also
1007 * for writing) if there is one.
1008 */
1009void VRDEServer::commit()
1010{
1011 /* sanity */
1012 AutoCaller autoCaller(this);
1013 AssertComRCReturnVoid(autoCaller.rc());
1014
1015 /* sanity too */
1016 AutoCaller peerCaller(mPeer);
1017 AssertComRCReturnVoid(peerCaller.rc());
1018
1019 /* lock both for writing since we modify both (mPeer is "master" so locked
1020 * first) */
1021 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1022
1023 if (mData.isBackedUp())
1024 {
1025 mData.commit();
1026 if (mPeer)
1027 {
1028 /* attach new data to the peer and reshare it */
1029 mPeer->mData.attach(mData);
1030 }
1031 }
1032}
1033
1034/**
1035 * @note Locks this object for writing, together with the peer object
1036 * represented by @a aThat (locked for reading).
1037 */
1038void VRDEServer::copyFrom(VRDEServer *aThat)
1039{
1040 AssertReturnVoid(aThat != NULL);
1041
1042 /* sanity */
1043 AutoCaller autoCaller(this);
1044 AssertComRCReturnVoid(autoCaller.rc());
1045
1046 /* sanity too */
1047 AutoCaller thatCaller(aThat);
1048 AssertComRCReturnVoid(thatCaller.rc());
1049
1050 /* peer is not modified, lock it for reading (aThat is "master" so locked
1051 * first) */
1052 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1053 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1054
1055 /* this will back up current data */
1056 mData.assignCopy(aThat->mData);
1057}
1058/* 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