VirtualBox

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

Last change on this file since 40257 was 38365, checked in by vboxsync, 13 years ago

Main/VRDE: default port

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