VirtualBox

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

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

Main: properly fixed the return code of VRDEServer::COMSETTER(Enabled) and fixed locking + some comments in ConsoleImpl

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.6 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(Enabled)(BOOL *aEnabled)
249{
250 CheckComArgOutPointerValid(aEnabled);
251
252 AutoCaller autoCaller(this);
253 if (FAILED(autoCaller.rc())) return autoCaller.rc();
254
255 *aEnabled = mData->mEnabled;
256
257 return S_OK;
258}
259
260STDMETHODIMP VRDEServer::COMSETTER(Enabled)(BOOL aEnabled)
261{
262 AutoCaller autoCaller(this);
263 if (FAILED(autoCaller.rc())) return autoCaller.rc();
264
265 /* the machine can also be in saved state for this property to change */
266 AutoMutableOrSavedStateDependency adep(mParent);
267 if (FAILED(adep.rc())) return adep.rc();
268
269 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
270
271 HRESULT rc = S_OK;
272
273 if (mData->mEnabled != aEnabled)
274 {
275 mData.backup();
276 mData->mEnabled = aEnabled;
277
278 /* leave the lock before informing callbacks */
279 alock.release();
280
281 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
282 mParent->setModified(Machine::IsModified_VRDEServer);
283 mlock.release();
284
285 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
286 adep.release();
287
288 rc = mParent->onVRDEServerChange(/* aRestart */ TRUE);
289 }
290
291 return rc;
292}
293
294static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
295{
296 /* Gets a string of digits, converts to 16 bit port number.
297 * Note: pszStart <= pszEnd is expected, the string contains
298 * only digits and pszEnd points to the char after last
299 * digit.
300 */
301 int cch = pszEnd - pszStart;
302 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
303 {
304 unsigned uPort = 0;
305 while (pszStart != pszEnd)
306 {
307 uPort = uPort * 10 + *pszStart - '0';
308 pszStart++;
309 }
310
311 if (uPort != 0 && uPort < 0x10000)
312 {
313 if (pu16Port)
314 *pu16Port = (uint16_t)uPort;
315 return VINF_SUCCESS;
316 }
317 }
318
319 return VERR_INVALID_PARAMETER;
320}
321
322static int vrdpServerVerifyPortsString(Bstr ports)
323{
324 com::Utf8Str portRange = ports;
325
326 const char *pszPortRange = portRange.c_str();
327
328 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
329 return VERR_INVALID_PARAMETER;
330
331 /* The string should be like "1000-1010,1020,2000-2003" */
332 while (*pszPortRange)
333 {
334 const char *pszStart = pszPortRange;
335 const char *pszDash = NULL;
336 const char *pszEnd = pszStart;
337
338 while (*pszEnd && *pszEnd != ',')
339 {
340 if (*pszEnd == '-')
341 {
342 if (pszDash != NULL)
343 return VERR_INVALID_PARAMETER; /* More than one '-'. */
344
345 pszDash = pszEnd;
346 }
347 else if (!RT_C_IS_DIGIT(*pszEnd))
348 return VERR_INVALID_PARAMETER;
349
350 pszEnd++;
351 }
352
353 /* Update the next range pointer. */
354 pszPortRange = pszEnd;
355 if (*pszPortRange == ',')
356 {
357 pszPortRange++;
358 }
359
360 /* A probably valid range. Verify and parse it. */
361 int rc;
362 if (pszDash)
363 {
364 rc = portParseNumber(NULL, pszStart, pszDash);
365 if (RT_SUCCESS(rc))
366 rc = portParseNumber(NULL, pszDash + 1, pszEnd);
367 }
368 else
369 rc = portParseNumber(NULL, pszStart, pszEnd);
370
371 if (RT_FAILURE(rc))
372 return rc;
373 }
374
375 return VINF_SUCCESS;
376}
377
378STDMETHODIMP VRDEServer::SetVRDEProperty(IN_BSTR aKey, IN_BSTR aValue)
379{
380 LogFlowThisFunc(("\n"));
381
382 AutoCaller autoCaller(this);
383 if (FAILED(autoCaller.rc())) return autoCaller.rc();
384
385 /* the machine can also be in saved state for this property to change */
386 AutoMutableOrSavedStateDependency adep(mParent);
387 if (FAILED(adep.rc())) return adep.rc();
388
389 Bstr key = aKey;
390
391 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 /* Special processing for some "standard" properties. */
394 if (key == Bstr("TCP/Ports"))
395 {
396 Bstr ports = aValue;
397
398 /* Verify the string. */
399 int vrc = vrdpServerVerifyPortsString(ports);
400 if (RT_FAILURE(vrc))
401 return E_INVALIDARG;
402
403 if (ports != mData->mProperties["TCP/Ports"])
404 {
405 /* Port value is not verified here because it is up to VRDP transport to
406 * use it. Specifying a wrong port number will cause a running server to
407 * stop. There is no fool proof here.
408 */
409 mData.backup();
410 if (ports == Bstr("0"))
411 mData->mProperties["TCP/Ports"] = VRDP_DEFAULT_PORT_STR;
412 else
413 mData->mProperties["TCP/Ports"] = ports;
414
415 /* leave the lock before informing callbacks */
416 alock.release();
417
418 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
419 mParent->setModified(Machine::IsModified_VRDEServer);
420 mlock.release();
421
422 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
423 adep.release();
424
425 mParent->onVRDEServerChange(/* aRestart */ TRUE);
426 }
427 }
428 else
429 {
430 /* Generic properties processing.
431 * Look up the old value first; if nothing's changed then do nothing.
432 */
433 Utf8Str strValue(aValue);
434 Utf8Str strKey(aKey);
435 Utf8Str strOldValue;
436
437 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
438 if (it != mData->mProperties.end())
439 strOldValue = it->second;
440
441 if (strOldValue != strValue)
442 {
443 if (strValue.isEmpty())
444 mData->mProperties.erase(strKey);
445 else
446 mData->mProperties[strKey] = strValue;
447
448 /* leave the lock before informing callbacks */
449 alock.release();
450
451 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
452 mParent->setModified(Machine::IsModified_VRDEServer);
453 mlock.release();
454
455 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
456 adep.release();
457
458 mParent->onVRDEServerChange(/* aRestart */ TRUE);
459 }
460 }
461
462 return S_OK;
463}
464
465STDMETHODIMP VRDEServer::GetVRDEProperty(IN_BSTR aKey, BSTR *aValue)
466{
467 CheckComArgOutPointerValid(aValue);
468
469 AutoCaller autoCaller(this);
470 if (FAILED(autoCaller.rc())) return autoCaller.rc();
471
472 Bstr key = aKey;
473 Bstr value;
474
475 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
476
477 Utf8Str strKey(key);
478 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
479 if (it != mData->mProperties.end())
480 value = it->second; // source is a Utf8Str
481 else if (strKey == "TCP/Ports")
482 value = VRDP_DEFAULT_PORT_STR;
483 value.cloneTo(aValue);
484
485 return S_OK;
486}
487
488static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
489{
490 int rc = VINF_SUCCESS;
491
492 RTLDRMOD hmod = NIL_RTLDRMOD;
493
494 RTERRINFOSTATIC ErrInfo;
495 RTErrInfoInitStatic(&ErrInfo);
496 if (RTPathHavePath(pszLibraryName))
497 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
498 else
499 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
500 if (RT_SUCCESS(rc))
501 {
502 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
503
504 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
505 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
506 }
507 else
508 {
509 if (RTErrInfoIsSet(&ErrInfo.Core))
510 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
511 else
512 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
513
514 hmod = NIL_RTLDRMOD;
515 }
516
517 if (RT_SUCCESS(rc))
518 {
519 *phmod = hmod;
520 }
521 else
522 {
523 if (hmod != NIL_RTLDRMOD)
524 {
525 RTLdrClose(hmod);
526 hmod = NIL_RTLDRMOD;
527 }
528 }
529
530 return rc;
531}
532
533STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProperties))
534{
535 if (ComSafeArrayOutIsNull(aProperties))
536 return E_POINTER;
537
538 AutoCaller autoCaller(this);
539 if (FAILED(autoCaller.rc())) return autoCaller.rc();
540
541 size_t cProperties = 0;
542
543 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
544 if (!mData->mEnabled)
545 {
546 com::SafeArray<BSTR> properties(cProperties);
547 properties.detachTo(ComSafeArrayOutArg(aProperties));
548 return S_OK;
549 }
550 alock.release();
551
552 /*
553 * Check that a VRDE extension pack name is set and resolve it into a
554 * library path.
555 */
556 Bstr bstrExtPack;
557 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
558 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
559 if (FAILED(hrc))
560 return hrc;
561 if (bstrExtPack.isEmpty())
562 return E_FAIL;
563
564 Utf8Str strExtPack(bstrExtPack);
565 Utf8Str strVrdeLibrary;
566 int vrc = VINF_SUCCESS;
567 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
568 strVrdeLibrary = "VBoxVRDP";
569 else
570 {
571#ifdef VBOX_WITH_EXTPACK
572 VirtualBox *pVirtualBox = mParent->getVirtualBox();
573 ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager();
574 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
575#else
576 vrc = VERR_FILE_NOT_FOUND;
577#endif
578 }
579 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
580
581 if (RT_SUCCESS(vrc))
582 {
583 /*
584 * Load the VRDE library and start the server, if it is enabled.
585 */
586 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
587 RTLDRMOD hmod = NIL_RTLDRMOD;
588 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
589 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
590 if (RT_SUCCESS(vrc))
591 {
592 const char * const *papszNames = pfn();
593
594 if (papszNames)
595 {
596 size_t i;
597 for (i = 0; papszNames[i] != NULL; ++i)
598 {
599 cProperties++;
600 }
601 }
602 Log(("VRDEPROP: %d properties\n", cProperties));
603
604 com::SafeArray<BSTR> properties(cProperties);
605
606 if (cProperties > 0)
607 {
608 size_t i;
609 for (i = 0; papszNames[i] != NULL && i < cProperties; ++i)
610 {
611 Bstr tmp(papszNames[i]);
612 tmp.cloneTo(&properties[i]);
613 }
614 }
615
616 /* Do not forget to unload the library. */
617 RTLdrClose(hmod);
618 hmod = NIL_RTLDRMOD;
619
620 properties.detachTo(ComSafeArrayOutArg(aProperties));
621 }
622 }
623
624 if (RT_FAILURE(vrc))
625 {
626 return E_FAIL;
627 }
628
629 return S_OK;
630}
631
632STDMETHODIMP VRDEServer::COMGETTER(AuthType)(AuthType_T *aType)
633{
634 CheckComArgOutPointerValid(aType);
635
636 AutoCaller autoCaller(this);
637 if (FAILED(autoCaller.rc())) return autoCaller.rc();
638
639 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
640
641 *aType = mData->mAuthType;
642
643 return S_OK;
644}
645
646STDMETHODIMP VRDEServer::COMSETTER(AuthType)(AuthType_T aType)
647{
648 AutoCaller autoCaller(this);
649 if (FAILED(autoCaller.rc())) return autoCaller.rc();
650
651 /* the machine can also be in saved state for this property to change */
652 AutoMutableOrSavedStateDependency adep(mParent);
653 if (FAILED(adep.rc())) return adep.rc();
654
655 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
656
657 if (mData->mAuthType != aType)
658 {
659 mData.backup();
660 mData->mAuthType = aType;
661
662 /* leave the lock before informing callbacks */
663 alock.release();
664
665 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
666 mParent->setModified(Machine::IsModified_VRDEServer);
667 mlock.release();
668
669 mParent->onVRDEServerChange(/* aRestart */ TRUE);
670 }
671
672 return S_OK;
673}
674
675STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout)(ULONG *aTimeout)
676{
677 CheckComArgOutPointerValid(aTimeout);
678
679 AutoCaller autoCaller(this);
680 if (FAILED(autoCaller.rc())) return autoCaller.rc();
681
682 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
683
684 *aTimeout = mData->mAuthTimeout;
685
686 return S_OK;
687}
688
689STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout)(ULONG aTimeout)
690{
691 AutoCaller autoCaller(this);
692 if (FAILED(autoCaller.rc())) return autoCaller.rc();
693
694 /* the machine can also be in saved state for this property to change */
695 AutoMutableOrSavedStateDependency adep(mParent);
696 if (FAILED(adep.rc())) return adep.rc();
697
698 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
699
700 if (aTimeout != mData->mAuthTimeout)
701 {
702 mData.backup();
703 mData->mAuthTimeout = aTimeout;
704
705 /* leave the lock before informing callbacks */
706 alock.release();
707
708 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
709 mParent->setModified(Machine::IsModified_VRDEServer);
710 mlock.release();
711
712 /* sunlover 20060131: This setter does not require the notification
713 * really */
714#if 0
715 mParent->onVRDEServerChange();
716#endif
717 }
718
719 return S_OK;
720}
721
722STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary)(BSTR *aLibrary)
723{
724 CheckComArgOutPointerValid(aLibrary);
725
726 AutoCaller autoCaller(this);
727 if (FAILED(autoCaller.rc())) return autoCaller.rc();
728
729 Bstr bstrLibrary;
730
731 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
732 bstrLibrary = mData->mAuthLibrary;
733 alock.release();
734
735 if (bstrLibrary.isEmpty())
736 {
737 /* Get the global setting. */
738 ComPtr<ISystemProperties> systemProperties;
739 HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
740
741 if (SUCCEEDED(hrc))
742 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());
743
744 if (FAILED(hrc))
745 return setError(hrc, "failed to query the library setting\n");
746 }
747
748 bstrLibrary.cloneTo(aLibrary);
749
750 return S_OK;
751}
752
753STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary)(IN_BSTR aLibrary)
754{
755 AutoCaller autoCaller(this);
756 if (FAILED(autoCaller.rc())) return autoCaller.rc();
757
758 /* the machine can also be in saved state for this property to change */
759 AutoMutableOrSavedStateDependency adep(mParent);
760 if (FAILED(adep.rc())) return adep.rc();
761
762 Bstr bstrLibrary(aLibrary);
763
764 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
765
766 if (mData->mAuthLibrary != bstrLibrary)
767 {
768 mData.backup();
769 mData->mAuthLibrary = bstrLibrary;
770
771 /* leave the lock before informing callbacks */
772 alock.release();
773
774 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
775 mParent->setModified(Machine::IsModified_VRDEServer);
776 mlock.release();
777
778 mParent->onVRDEServerChange(/* aRestart */ TRUE);
779 }
780
781 return S_OK;
782}
783
784STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection)(BOOL *aAllowMultiConnection)
785{
786 CheckComArgOutPointerValid(aAllowMultiConnection);
787
788 AutoCaller autoCaller(this);
789 if (FAILED(autoCaller.rc())) return autoCaller.rc();
790
791 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
792
793 *aAllowMultiConnection = mData->mAllowMultiConnection;
794
795 return S_OK;
796}
797
798STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection)(BOOL aAllowMultiConnection)
799{
800 AutoCaller autoCaller(this);
801 if (FAILED(autoCaller.rc())) return autoCaller.rc();
802
803 /* the machine can also be in saved state for this property to change */
804 AutoMutableOrSavedStateDependency adep(mParent);
805 if (FAILED(adep.rc())) return adep.rc();
806
807 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
808
809 if (mData->mAllowMultiConnection != aAllowMultiConnection)
810 {
811 mData.backup();
812 mData->mAllowMultiConnection = aAllowMultiConnection;
813
814 /* leave the lock before informing callbacks */
815 alock.release();
816
817 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
818 mParent->setModified(Machine::IsModified_VRDEServer);
819 mlock.release();
820
821 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
822 }
823
824 return S_OK;
825}
826
827STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection)(BOOL *aReuseSingleConnection)
828{
829 CheckComArgOutPointerValid(aReuseSingleConnection);
830
831 AutoCaller autoCaller(this);
832 if (FAILED(autoCaller.rc())) return autoCaller.rc();
833
834 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
835
836 *aReuseSingleConnection = mData->mReuseSingleConnection;
837
838 return S_OK;
839}
840
841STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection)(BOOL aReuseSingleConnection)
842{
843 AutoCaller autoCaller(this);
844 if (FAILED(autoCaller.rc())) return autoCaller.rc();
845
846 /* the machine can also be in saved state for this property to change */
847 AutoMutableOrSavedStateDependency adep(mParent);
848 if (FAILED(adep.rc())) return adep.rc();
849
850 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
851
852 if (mData->mReuseSingleConnection != aReuseSingleConnection)
853 {
854 mData.backup();
855 mData->mReuseSingleConnection = aReuseSingleConnection;
856
857 /* leave the lock before informing callbacks */
858 alock.release();
859
860 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
861 mParent->setModified(Machine::IsModified_VRDEServer);
862 mlock.release();
863
864 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo needs a restart?
865 }
866
867 return S_OK;
868}
869
870STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack)(BSTR *aExtPack)
871{
872 CheckComArgOutPointerValid(aExtPack);
873
874 AutoCaller autoCaller(this);
875 HRESULT hrc = autoCaller.rc();
876 if (SUCCEEDED(hrc))
877 {
878 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
879 Utf8Str strExtPack = mData->mVrdeExtPack;
880 alock.release();
881
882 if (strExtPack.isNotEmpty())
883 {
884 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
885 hrc = S_OK;
886 else
887 {
888#ifdef VBOX_WITH_EXTPACK
889 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
890 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
891#else
892 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
893#endif
894 }
895 if (SUCCEEDED(hrc))
896 strExtPack.cloneTo(aExtPack);
897 }
898 else
899 {
900 /* Get the global setting. */
901 ComPtr<ISystemProperties> systemProperties;
902 hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
903 if (SUCCEEDED(hrc))
904 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(aExtPack);
905 }
906 }
907
908 return hrc;
909}
910
911STDMETHODIMP VRDEServer::COMSETTER(VRDEExtPack)(IN_BSTR aExtPack)
912{
913 CheckComArgNotNull(aExtPack);
914 Utf8Str strExtPack(aExtPack);
915
916 AutoCaller autoCaller(this);
917 HRESULT hrc = autoCaller.rc();
918 if (SUCCEEDED(hrc))
919 {
920 /* the machine can also be in saved state for this property to change */
921 AutoMutableOrSavedStateDependency adep(mParent);
922 hrc = adep.rc();
923 if (SUCCEEDED(hrc))
924 {
925 /*
926 * If not empty, check the specific extension pack.
927 */
928 if (!strExtPack.isEmpty())
929 {
930 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
931 hrc = S_OK;
932 else
933 {
934#ifdef VBOX_WITH_EXTPACK
935 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
936 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
937#else
938 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
939#endif
940 }
941 }
942 if (SUCCEEDED(hrc))
943 {
944 /*
945 * Update the setting if there is an actual change, post an
946 * change event to trigger a VRDE server restart.
947 */
948 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
949 if (strExtPack != mData->mVrdeExtPack)
950 {
951 mData.backup();
952 mData->mVrdeExtPack = strExtPack;
953
954 /* leave the lock before informing callbacks */
955 alock.release();
956
957 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
958 mParent->setModified(Machine::IsModified_VRDEServer);
959 mlock.release();
960
961 mParent->onVRDEServerChange(/* aRestart */ TRUE);
962 }
963 }
964 }
965 }
966
967 return hrc;
968}
969
970// public methods only for internal purposes
971/////////////////////////////////////////////////////////////////////////////
972
973/**
974 * @note Locks this object for writing.
975 */
976void VRDEServer::rollback()
977{
978 /* sanity */
979 AutoCaller autoCaller(this);
980 AssertComRCReturnVoid(autoCaller.rc());
981
982 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
983
984 mData.rollback();
985}
986
987/**
988 * @note Locks this object for writing, together with the peer object (also
989 * for writing) if there is one.
990 */
991void VRDEServer::commit()
992{
993 /* sanity */
994 AutoCaller autoCaller(this);
995 AssertComRCReturnVoid(autoCaller.rc());
996
997 /* sanity too */
998 AutoCaller peerCaller(mPeer);
999 AssertComRCReturnVoid(peerCaller.rc());
1000
1001 /* lock both for writing since we modify both (mPeer is "master" so locked
1002 * first) */
1003 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1004
1005 if (mData.isBackedUp())
1006 {
1007 mData.commit();
1008 if (mPeer)
1009 {
1010 /* attach new data to the peer and reshare it */
1011 mPeer->mData.attach(mData);
1012 }
1013 }
1014}
1015
1016/**
1017 * @note Locks this object for writing, together with the peer object
1018 * represented by @a aThat (locked for reading).
1019 */
1020void VRDEServer::copyFrom(VRDEServer *aThat)
1021{
1022 AssertReturnVoid(aThat != NULL);
1023
1024 /* sanity */
1025 AutoCaller autoCaller(this);
1026 AssertComRCReturnVoid(autoCaller.rc());
1027
1028 /* sanity too */
1029 AutoCaller thatCaller(aThat);
1030 AssertComRCReturnVoid(thatCaller.rc());
1031
1032 /* peer is not modified, lock it for reading (aThat is "master" so locked
1033 * first) */
1034 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1035 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1036
1037 /* this will back up current data */
1038 mData.assignCopy(aThat->mData);
1039}
1040/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette