VirtualBox

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

Last change on this file since 47469 was 46820, checked in by vboxsync, 11 years ago

Main: do not include VirtualBoxImpl.h from code ending in VBoxC (causes unnecessary rebuilds), and make sure that the code still builds with VBOX_WITH_RESOURCE_USAGE_API unset

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.7 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#include <VBox/com/array.h>
33
34#include <VBox/RemoteDesktop/VRDE.h>
35
36#include "AutoStateDep.h"
37#include "AutoCaller.h"
38#include "Global.h"
39#include "Logging.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 /* the machine can also be in saved state for this property to change */
267 AutoMutableOrSavedStateDependency adep(mParent);
268 if (FAILED(adep.rc())) return adep.rc();
269
270 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
271
272 HRESULT rc = S_OK;
273
274 if (mData->mEnabled != aEnabled)
275 {
276 mData.backup();
277 mData->mEnabled = aEnabled;
278
279 /* leave the lock before informing callbacks */
280 alock.release();
281
282 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
283 mParent->setModified(Machine::IsModified_VRDEServer);
284 mlock.release();
285
286 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
287 adep.release();
288
289 rc = mParent->onVRDEServerChange(/* aRestart */ TRUE);
290 }
291
292 return rc;
293}
294
295static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
296{
297 /* Gets a string of digits, converts to 16 bit port number.
298 * Note: pszStart <= pszEnd is expected, the string contains
299 * only digits and pszEnd points to the char after last
300 * digit.
301 */
302 int cch = pszEnd - pszStart;
303 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
304 {
305 unsigned uPort = 0;
306 while (pszStart != pszEnd)
307 {
308 uPort = uPort * 10 + *pszStart - '0';
309 pszStart++;
310 }
311
312 if (uPort != 0 && uPort < 0x10000)
313 {
314 if (pu16Port)
315 *pu16Port = (uint16_t)uPort;
316 return VINF_SUCCESS;
317 }
318 }
319
320 return VERR_INVALID_PARAMETER;
321}
322
323static int vrdpServerVerifyPortsString(Bstr ports)
324{
325 com::Utf8Str portRange = ports;
326
327 const char *pszPortRange = portRange.c_str();
328
329 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
330 return VERR_INVALID_PARAMETER;
331
332 /* The string should be like "1000-1010,1020,2000-2003" */
333 while (*pszPortRange)
334 {
335 const char *pszStart = pszPortRange;
336 const char *pszDash = NULL;
337 const char *pszEnd = pszStart;
338
339 while (*pszEnd && *pszEnd != ',')
340 {
341 if (*pszEnd == '-')
342 {
343 if (pszDash != NULL)
344 return VERR_INVALID_PARAMETER; /* More than one '-'. */
345
346 pszDash = pszEnd;
347 }
348 else if (!RT_C_IS_DIGIT(*pszEnd))
349 return VERR_INVALID_PARAMETER;
350
351 pszEnd++;
352 }
353
354 /* Update the next range pointer. */
355 pszPortRange = pszEnd;
356 if (*pszPortRange == ',')
357 {
358 pszPortRange++;
359 }
360
361 /* A probably valid range. Verify and parse it. */
362 int rc;
363 if (pszDash)
364 {
365 rc = portParseNumber(NULL, pszStart, pszDash);
366 if (RT_SUCCESS(rc))
367 rc = portParseNumber(NULL, pszDash + 1, pszEnd);
368 }
369 else
370 rc = portParseNumber(NULL, pszStart, pszEnd);
371
372 if (RT_FAILURE(rc))
373 return rc;
374 }
375
376 return VINF_SUCCESS;
377}
378
379STDMETHODIMP VRDEServer::SetVRDEProperty(IN_BSTR aKey, IN_BSTR aValue)
380{
381 LogFlowThisFunc(("\n"));
382
383 AutoCaller autoCaller(this);
384 if (FAILED(autoCaller.rc())) return autoCaller.rc();
385
386 /* the machine can also be in saved state for this property to change */
387 AutoMutableOrSavedStateDependency adep(mParent);
388 if (FAILED(adep.rc())) return adep.rc();
389
390 Bstr key = aKey;
391
392 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
393
394 /* Special processing for some "standard" properties. */
395 if (key == Bstr("TCP/Ports"))
396 {
397 Bstr ports = aValue;
398
399 /* Verify the string. */
400 int vrc = vrdpServerVerifyPortsString(ports);
401 if (RT_FAILURE(vrc))
402 return E_INVALIDARG;
403
404 if (ports != mData->mProperties["TCP/Ports"])
405 {
406 /* Port value is not verified here because it is up to VRDP transport to
407 * use it. Specifying a wrong port number will cause a running server to
408 * stop. There is no fool proof here.
409 */
410 mData.backup();
411 if (ports == Bstr("0"))
412 mData->mProperties["TCP/Ports"] = VRDP_DEFAULT_PORT_STR;
413 else
414 mData->mProperties["TCP/Ports"] = ports;
415
416 /* leave the lock before informing callbacks */
417 alock.release();
418
419 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
420 mParent->setModified(Machine::IsModified_VRDEServer);
421 mlock.release();
422
423 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
424 adep.release();
425
426 mParent->onVRDEServerChange(/* aRestart */ TRUE);
427 }
428 }
429 else
430 {
431 /* Generic properties processing.
432 * Look up the old value first; if nothing's changed then do nothing.
433 */
434 Utf8Str strValue(aValue);
435 Utf8Str strKey(aKey);
436 Utf8Str strOldValue;
437
438 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
439 if (it != mData->mProperties.end())
440 strOldValue = it->second;
441
442 if (strOldValue != strValue)
443 {
444 if (strValue.isEmpty())
445 mData->mProperties.erase(strKey);
446 else
447 mData->mProperties[strKey] = strValue;
448
449 /* leave the lock before informing callbacks */
450 alock.release();
451
452 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
453 mParent->setModified(Machine::IsModified_VRDEServer);
454 mlock.release();
455
456 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
457 adep.release();
458
459 mParent->onVRDEServerChange(/* aRestart */ TRUE);
460 }
461 }
462
463 return S_OK;
464}
465
466STDMETHODIMP VRDEServer::GetVRDEProperty(IN_BSTR aKey, BSTR *aValue)
467{
468 CheckComArgOutPointerValid(aValue);
469
470 AutoCaller autoCaller(this);
471 if (FAILED(autoCaller.rc())) return autoCaller.rc();
472
473 Bstr key = aKey;
474 Bstr value;
475
476 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
477
478 Utf8Str strKey(key);
479 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
480 if (it != mData->mProperties.end())
481 value = it->second; // source is a Utf8Str
482 else if (strKey == "TCP/Ports")
483 value = VRDP_DEFAULT_PORT_STR;
484 value.cloneTo(aValue);
485
486 return S_OK;
487}
488
489static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
490{
491 int rc = VINF_SUCCESS;
492
493 RTLDRMOD hmod = NIL_RTLDRMOD;
494
495 RTERRINFOSTATIC ErrInfo;
496 RTErrInfoInitStatic(&ErrInfo);
497 if (RTPathHavePath(pszLibraryName))
498 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
499 else
500 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
501 if (RT_SUCCESS(rc))
502 {
503 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
504
505 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
506 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
507 }
508 else
509 {
510 if (RTErrInfoIsSet(&ErrInfo.Core))
511 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
512 else
513 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
514
515 hmod = NIL_RTLDRMOD;
516 }
517
518 if (RT_SUCCESS(rc))
519 {
520 *phmod = hmod;
521 }
522 else
523 {
524 if (hmod != NIL_RTLDRMOD)
525 {
526 RTLdrClose(hmod);
527 hmod = NIL_RTLDRMOD;
528 }
529 }
530
531 return rc;
532}
533
534STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProperties))
535{
536 if (ComSafeArrayOutIsNull(aProperties))
537 return E_POINTER;
538
539 AutoCaller autoCaller(this);
540 if (FAILED(autoCaller.rc())) return autoCaller.rc();
541
542 size_t cProperties = 0;
543
544 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
545 if (!mData->mEnabled)
546 {
547 com::SafeArray<BSTR> properties(cProperties);
548 properties.detachTo(ComSafeArrayOutArg(aProperties));
549 return S_OK;
550 }
551 alock.release();
552
553 /*
554 * Check that a VRDE extension pack name is set and resolve it into a
555 * library path.
556 */
557 Bstr bstrExtPack;
558 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
559 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
560 if (FAILED(hrc))
561 return hrc;
562 if (bstrExtPack.isEmpty())
563 return E_FAIL;
564
565 Utf8Str strExtPack(bstrExtPack);
566 Utf8Str strVrdeLibrary;
567 int vrc = VINF_SUCCESS;
568 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
569 strVrdeLibrary = "VBoxVRDP";
570 else
571 {
572#ifdef VBOX_WITH_EXTPACK
573 VirtualBox *pVirtualBox = mParent->getVirtualBox();
574 ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager();
575 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
576#else
577 vrc = VERR_FILE_NOT_FOUND;
578#endif
579 }
580 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
581
582 if (RT_SUCCESS(vrc))
583 {
584 /*
585 * Load the VRDE library and start the server, if it is enabled.
586 */
587 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
588 RTLDRMOD hmod = NIL_RTLDRMOD;
589 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
590 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
591 if (RT_SUCCESS(vrc))
592 {
593 const char * const *papszNames = pfn();
594
595 if (papszNames)
596 {
597 size_t i;
598 for (i = 0; papszNames[i] != NULL; ++i)
599 {
600 cProperties++;
601 }
602 }
603 Log(("VRDEPROP: %d properties\n", cProperties));
604
605 com::SafeArray<BSTR> properties(cProperties);
606
607 if (cProperties > 0)
608 {
609 size_t i;
610 for (i = 0; papszNames[i] != NULL && i < cProperties; ++i)
611 {
612 Bstr tmp(papszNames[i]);
613 tmp.cloneTo(&properties[i]);
614 }
615 }
616
617 /* Do not forget to unload the library. */
618 RTLdrClose(hmod);
619 hmod = NIL_RTLDRMOD;
620
621 properties.detachTo(ComSafeArrayOutArg(aProperties));
622 }
623 }
624
625 if (RT_FAILURE(vrc))
626 {
627 return E_FAIL;
628 }
629
630 return S_OK;
631}
632
633STDMETHODIMP VRDEServer::COMGETTER(AuthType)(AuthType_T *aType)
634{
635 CheckComArgOutPointerValid(aType);
636
637 AutoCaller autoCaller(this);
638 if (FAILED(autoCaller.rc())) return autoCaller.rc();
639
640 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
641
642 *aType = mData->mAuthType;
643
644 return S_OK;
645}
646
647STDMETHODIMP VRDEServer::COMSETTER(AuthType)(AuthType_T aType)
648{
649 AutoCaller autoCaller(this);
650 if (FAILED(autoCaller.rc())) return autoCaller.rc();
651
652 /* the machine can also be in saved state for this property to change */
653 AutoMutableOrSavedStateDependency adep(mParent);
654 if (FAILED(adep.rc())) return adep.rc();
655
656 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
657
658 if (mData->mAuthType != aType)
659 {
660 mData.backup();
661 mData->mAuthType = aType;
662
663 /* leave the lock before informing callbacks */
664 alock.release();
665
666 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
667 mParent->setModified(Machine::IsModified_VRDEServer);
668 mlock.release();
669
670 mParent->onVRDEServerChange(/* aRestart */ TRUE);
671 }
672
673 return S_OK;
674}
675
676STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout)(ULONG *aTimeout)
677{
678 CheckComArgOutPointerValid(aTimeout);
679
680 AutoCaller autoCaller(this);
681 if (FAILED(autoCaller.rc())) return autoCaller.rc();
682
683 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
684
685 *aTimeout = mData->mAuthTimeout;
686
687 return S_OK;
688}
689
690STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout)(ULONG aTimeout)
691{
692 AutoCaller autoCaller(this);
693 if (FAILED(autoCaller.rc())) return autoCaller.rc();
694
695 /* the machine can also be in saved state for this property to change */
696 AutoMutableOrSavedStateDependency adep(mParent);
697 if (FAILED(adep.rc())) return adep.rc();
698
699 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
700
701 if (aTimeout != mData->mAuthTimeout)
702 {
703 mData.backup();
704 mData->mAuthTimeout = aTimeout;
705
706 /* leave the lock before informing callbacks */
707 alock.release();
708
709 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
710 mParent->setModified(Machine::IsModified_VRDEServer);
711 mlock.release();
712
713 /* sunlover 20060131: This setter does not require the notification
714 * really */
715#if 0
716 mParent->onVRDEServerChange();
717#endif
718 }
719
720 return S_OK;
721}
722
723STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary)(BSTR *aLibrary)
724{
725 CheckComArgOutPointerValid(aLibrary);
726
727 AutoCaller autoCaller(this);
728 if (FAILED(autoCaller.rc())) return autoCaller.rc();
729
730 Bstr bstrLibrary;
731
732 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
733 bstrLibrary = mData->mAuthLibrary;
734 alock.release();
735
736 if (bstrLibrary.isEmpty())
737 {
738 /* Get the global setting. */
739 ComPtr<ISystemProperties> systemProperties;
740 HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
741
742 if (SUCCEEDED(hrc))
743 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());
744
745 if (FAILED(hrc))
746 return setError(hrc, "failed to query the library setting\n");
747 }
748
749 bstrLibrary.cloneTo(aLibrary);
750
751 return S_OK;
752}
753
754STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary)(IN_BSTR aLibrary)
755{
756 AutoCaller autoCaller(this);
757 if (FAILED(autoCaller.rc())) return autoCaller.rc();
758
759 /* the machine can also be in saved state for this property to change */
760 AutoMutableOrSavedStateDependency adep(mParent);
761 if (FAILED(adep.rc())) return adep.rc();
762
763 Bstr bstrLibrary(aLibrary);
764
765 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
766
767 if (mData->mAuthLibrary != bstrLibrary)
768 {
769 mData.backup();
770 mData->mAuthLibrary = bstrLibrary;
771
772 /* leave the lock before informing callbacks */
773 alock.release();
774
775 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
776 mParent->setModified(Machine::IsModified_VRDEServer);
777 mlock.release();
778
779 mParent->onVRDEServerChange(/* aRestart */ TRUE);
780 }
781
782 return S_OK;
783}
784
785STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection)(BOOL *aAllowMultiConnection)
786{
787 CheckComArgOutPointerValid(aAllowMultiConnection);
788
789 AutoCaller autoCaller(this);
790 if (FAILED(autoCaller.rc())) return autoCaller.rc();
791
792 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
793
794 *aAllowMultiConnection = mData->mAllowMultiConnection;
795
796 return S_OK;
797}
798
799STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection)(BOOL aAllowMultiConnection)
800{
801 AutoCaller autoCaller(this);
802 if (FAILED(autoCaller.rc())) return autoCaller.rc();
803
804 /* the machine can also be in saved state for this property to change */
805 AutoMutableOrSavedStateDependency adep(mParent);
806 if (FAILED(adep.rc())) return adep.rc();
807
808 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
809
810 if (mData->mAllowMultiConnection != aAllowMultiConnection)
811 {
812 mData.backup();
813 mData->mAllowMultiConnection = aAllowMultiConnection;
814
815 /* leave the lock before informing callbacks */
816 alock.release();
817
818 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
819 mParent->setModified(Machine::IsModified_VRDEServer);
820 mlock.release();
821
822 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
823 }
824
825 return S_OK;
826}
827
828STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection)(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)(BOOL aReuseSingleConnection)
843{
844 AutoCaller autoCaller(this);
845 if (FAILED(autoCaller.rc())) return autoCaller.rc();
846
847 /* the machine can also be in saved state for this property to change */
848 AutoMutableOrSavedStateDependency 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 can also be in saved state for this property to change */
922 AutoMutableOrSavedStateDependency 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.

© 2023 Oracle
ContactPrivacy policyTerms of Use