VirtualBox

source: vbox/trunk/src/VBox/Main/VRDEServerImpl.cpp@ 35242

Last change on this file since 35242 was 35191, checked in by vboxsync, 14 years ago

Some cleanup. Pass RTLDRLOAD_FLAGS_LOCAL instead of 0, since it's defined.

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