VirtualBox

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

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

Main/Machine: temporary workaround

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