VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp@ 79294

Last change on this file since 79294 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.8 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2010-2019 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#define LOG_GROUP LOG_GROUP_MAIN_VIRTUALBOXCLIENT
19#include "LoggingNew.h"
20
21#include "VirtualBoxClientImpl.h"
22
23#include "AutoCaller.h"
24#include "VBoxEvents.h"
25#include "VBox/com/ErrorInfo.h"
26
27#include <iprt/asm.h>
28#include <iprt/thread.h>
29#include <iprt/critsect.h>
30#include <iprt/semaphore.h>
31#include <iprt/cpp/utils.h>
32#include <iprt/utf16.h>
33#ifdef RT_OS_WINDOWS
34# include <iprt/err.h>
35# include <iprt/ldr.h>
36# include <msi.h>
37# include <WbemIdl.h>
38#endif
39
40
41/** Waiting time between probing whether VBoxSVC is alive. */
42#define VBOXCLIENT_DEFAULT_INTERVAL 30000
43
44
45/** Initialize instance counter class variable */
46uint32_t VirtualBoxClient::g_cInstances = 0;
47
48LONG VirtualBoxClient::s_cUnnecessaryAtlModuleLocks = 0;
49
50// constructor / destructor
51/////////////////////////////////////////////////////////////////////////////
52
53HRESULT VirtualBoxClient::FinalConstruct()
54{
55 HRESULT rc = init();
56 BaseFinalConstruct();
57 return rc;
58}
59
60void VirtualBoxClient::FinalRelease()
61{
62 uninit();
63 BaseFinalRelease();
64}
65
66
67// public initializer/uninitializer for internal purposes only
68/////////////////////////////////////////////////////////////////////////////
69
70/**
71 * Initializes the VirtualBoxClient object.
72 *
73 * @returns COM result indicator
74 */
75HRESULT VirtualBoxClient::init()
76{
77
78#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_SDS)
79 // setup COM Security to enable impersonation
80 // This works for console VirtualBox clients, GUI has own security settings
81 // For GUI VirtualBox it will be second call so can return TOO_LATE error
82 HRESULT hrGUICoInitializeSecurity = CoInitializeSecurity(NULL,
83 -1,
84 NULL,
85 NULL,
86 RPC_C_AUTHN_LEVEL_DEFAULT,
87 RPC_C_IMP_LEVEL_IMPERSONATE,
88 NULL,
89 EOAC_NONE,
90 NULL);
91 NOREF(hrGUICoInitializeSecurity);
92 Assert(SUCCEEDED(hrGUICoInitializeSecurity) || hrGUICoInitializeSecurity == RPC_E_TOO_LATE);
93#endif
94
95 LogFlowThisFuncEnter();
96
97 /* Enclose the state transition NotReady->InInit->Ready */
98 AutoInitSpan autoInitSpan(this);
99 AssertReturn(autoInitSpan.isOk(), E_FAIL);
100
101 /* Important: DO NOT USE any kind of "early return" (except the single
102 * one above, checking the init span success) in this method. It is vital
103 * for correct error handling that it has only one point of return, which
104 * does all the magic on COM to signal object creation success and
105 * reporting the error later for every API method. COM translates any
106 * unsuccessful object creation to REGDB_E_CLASSNOTREG errors or similar
107 * unhelpful ones which cause us a lot of grief with troubleshooting. */
108
109 HRESULT rc = S_OK;
110 try
111 {
112 if (ASMAtomicIncU32(&g_cInstances) != 1)
113 AssertFailedStmt(throw setError(E_FAIL, tr("Attempted to create more than one VirtualBoxClient instance")));
114
115 mData.m_ThreadWatcher = NIL_RTTHREAD;
116 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
117
118 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox);
119 if (FAILED(rc))
120#ifdef RT_OS_WINDOWS
121 throw i_investigateVirtualBoxObjectCreationFailure(rc);
122#else
123 throw rc;
124#endif
125
126 /* VirtualBox error return is postponed to method calls, fetch it. */
127 ULONG rev;
128 rc = mData.m_pVirtualBox->COMGETTER(Revision)(&rev);
129 if (FAILED(rc))
130 throw rc;
131
132 rc = unconst(mData.m_pEventSource).createObject();
133 AssertComRCThrow(rc, setError(rc, tr("Could not create EventSource for VirtualBoxClient")));
134 rc = mData.m_pEventSource->init();
135 AssertComRCThrow(rc, setError(rc, tr("Could not initialize EventSource for VirtualBoxClient")));
136
137 /* HACK ALERT! This is for DllCanUnloadNow(). */
138 s_cUnnecessaryAtlModuleLocks++;
139 AssertMsg(s_cUnnecessaryAtlModuleLocks == 1, ("%d\n", s_cUnnecessaryAtlModuleLocks));
140
141 /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it
142 * is not considered important enough to cause any sort of visible
143 * failure. The monitoring will not be done, but that's all. */
144 int vrc = RTSemEventCreate(&mData.m_SemEvWatcher);
145 if (RT_FAILURE(vrc))
146 {
147 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
148 AssertRCStmt(vrc, throw setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to create semaphore (rc=%Rrc)"), vrc));
149 }
150
151 vrc = RTThreadCreate(&mData.m_ThreadWatcher, SVCWatcherThread, this, 0,
152 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "VBoxSVCWatcher");
153 if (RT_FAILURE(vrc))
154 {
155 RTSemEventDestroy(mData.m_SemEvWatcher);
156 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
157 AssertRCStmt(vrc, throw setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to create watcher thread (rc=%Rrc)"), vrc));
158 }
159 }
160 catch (HRESULT err)
161 {
162 /* we assume that error info is set by the thrower */
163 rc = err;
164 }
165 catch (...)
166 {
167 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS);
168 }
169
170 /* Confirm a successful initialization when it's the case. Must be last,
171 * as on failure it will uninitialize the object. */
172 if (SUCCEEDED(rc))
173 autoInitSpan.setSucceeded();
174 else
175 autoInitSpan.setFailed(rc);
176
177 LogFlowThisFunc(("rc=%Rhrc\n", rc));
178 LogFlowThisFuncLeave();
179 /* Unconditionally return success, because the error return is delayed to
180 * the attribute/method calls through the InitFailed object state. */
181 return S_OK;
182}
183
184#ifdef RT_OS_WINDOWS
185
186/**
187 * Looks into why we failed to create the VirtualBox object.
188 *
189 * @returns hrcCaller thru setError.
190 * @param hrcCaller The failure status code.
191 */
192HRESULT VirtualBoxClient::i_investigateVirtualBoxObjectCreationFailure(HRESULT hrcCaller)
193{
194 HRESULT hrc;
195
196# ifdef VBOX_WITH_SDS
197 /*
198 * Check that the VBoxSDS service is configured to run as LocalSystem and is enabled.
199 */
200 WCHAR wszBuffer[256];
201 uint32_t uStartType;
202 int vrc = i_getServiceAccountAndStartType(L"VBoxSDS", wszBuffer, RT_ELEMENTS(wszBuffer), &uStartType);
203 if (RT_SUCCESS(vrc))
204 {
205 LogRelFunc(("VBoxSDS service is running under the '%ls' account with start type %u.\n", wszBuffer, uStartType));
206 if (RTUtf16Cmp(wszBuffer, L"LocalSystem") != 0)
207 return setError(hrcCaller,
208 tr("VBoxSDS is misconfigured to run under the '%ls' account instead of the SYSTEM one.\n"
209 "Reinstall VirtualBox to fix it. Alternatively you can fix it using the Windows Service Control "
210 "Manager or by running 'qc config VBoxSDS obj=LocalSystem' on a command line."), wszBuffer);
211 if (uStartType == SERVICE_DISABLED)
212 return setError(hrcCaller,
213 tr("The VBoxSDS windows service is disabled.\n"
214 "Reinstall VirtualBox to fix it. Alternatively try reenable the service by setting it to "
215 " 'Manual' startup type in the Windows Service management console, or by runing "
216 "'sc config VBoxSDS start=demand' on the command line."));
217 }
218 else if (vrc == VERR_NOT_FOUND)
219 return setError(hrcCaller,
220 tr("The VBoxSDS windows service was not found.\n"
221 "Reinstall VirtualBox to fix it. Alternatively you can try start VirtualBox as Administrator, this "
222 "should automatically reinstall the service, or you can run "
223 "'VBoxSDS.exe --regservice' command from an elevated Administrator command line."));
224 else
225 LogRelFunc(("VirtualBoxClient::i_getServiceAccount failed: %Rrc\n", vrc));
226# endif
227
228 /*
229 * First step is to try get an IUnknown interface of the VirtualBox object.
230 *
231 * This will succeed even when oleaut32.msm (see @bugref{8016}, @ticketref{12087})
232 * is accidentally installed and messes up COM. It may also succeed when the COM
233 * registration is partially broken (though that's unlikely to happen these days).
234 */
235 IUnknown *pUnknown = NULL;
236 hrc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
237 if (FAILED(hrc))
238 {
239 if (hrc == hrcCaller)
240 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc"), hrcCaller);
241 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc & %Rhrc"), hrcCaller, hrc);
242 }
243
244 /*
245 * Try query the IVirtualBox interface (should fail), if it succeed we return
246 * straight away so we have more columns to spend on long messages below.
247 */
248 IVirtualBox *pVirtualBox;
249 hrc = pUnknown->QueryInterface(IID_IVirtualBox, (void **)&pVirtualBox);
250 if (SUCCEEDED(hrc))
251 {
252 pVirtualBox->Release();
253 pUnknown->Release();
254 return setError(hrcCaller,
255 tr("Failed to instantiate CLSID_VirtualBox the first time, but worked when checking out why ... weird"));
256 }
257
258 /*
259 * Check for oleaut32.msm traces in the registry.
260 */
261 HKEY hKey;
262 LSTATUS lrc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer32",
263 0 /*fFlags*/, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | STANDARD_RIGHTS_READ, &hKey);
264 if (lrc == ERROR_SUCCESS)
265 {
266 wchar_t wszBuf[8192];
267 DWORD cbBuf = sizeof(wszBuf) - sizeof(wchar_t);
268 DWORD dwType = 0;
269 lrc = RegQueryValueExW(hKey, L"InprocServer32", NULL /*pvReserved*/, &dwType, (BYTE *)&wszBuf[0], &cbBuf);
270 if (lrc == ERROR_SUCCESS)
271 {
272 wszBuf[cbBuf / sizeof(wchar_t)] = '\0';
273 bool fSetError = false;
274
275 /*
276 * Try decode the string and improve the message.
277 */
278 typedef UINT (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor,
279 LPWSTR pwszProductCode /*[40]*/,
280 LPWSTR pwszFeatureId /*[40]*/,
281 LPWSTR pwszComponentCode /*[40]*/,
282 DWORD *poffArguments);
283 PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW;
284 pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)RTLdrGetSystemSymbol("msi.dll", "MsiDecomposeDescriptorW");
285 if ( pfnMsiDecomposeDescriptorW
286 && ( dwType == REG_SZ
287 || dwType == REG_MULTI_SZ))
288 {
289 wchar_t wszProductCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
290 wchar_t wszFeatureId[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
291 wchar_t wszComponentCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
292 DWORD offArguments = ~(DWORD)0;
293 UINT uRc = pfnMsiDecomposeDescriptorW(wszBuf, wszProductCode, wszFeatureId, wszComponentCode, &offArguments);
294 if (uRc == 0)
295 {
296 /*
297 * Can we resolve the product code into a name?
298 */
299 typedef UINT (WINAPI *PFNMSIOPENPRODUCTW)(PCWSTR, MSIHANDLE *);
300 PFNMSIOPENPRODUCTW pfnMsiOpenProductW;
301 pfnMsiOpenProductW = (PFNMSIOPENPRODUCTW)RTLdrGetSystemSymbol("msi.dll", "MsiOpenProductW");
302
303 typedef UINT (WINAPI *PFNMSICLOSEHANDLE)(MSIHANDLE);
304 PFNMSICLOSEHANDLE pfnMsiCloseHandle;
305 pfnMsiCloseHandle = (PFNMSICLOSEHANDLE)RTLdrGetSystemSymbol("msi.dll", "MsiCloseHandle");
306
307 typedef UINT (WINAPI *PFNGETPRODUCTPROPERTYW)(MSIHANDLE, PCWSTR, PWSTR, PDWORD);
308 PFNGETPRODUCTPROPERTYW pfnMsiGetProductPropertyW;
309 pfnMsiGetProductPropertyW = (PFNGETPRODUCTPROPERTYW)RTLdrGetSystemSymbol("msi.dll", "MsiGetProductPropertyW");
310 if ( pfnMsiGetProductPropertyW
311 && pfnMsiCloseHandle
312 && pfnMsiOpenProductW)
313 {
314 MSIHANDLE hMsi = 0;
315 uRc = pfnMsiOpenProductW(wszProductCode, &hMsi);
316 if (uRc == 0)
317 {
318 static wchar_t const * const s_apwszProps[] =
319 {
320 INSTALLPROPERTY_INSTALLEDPRODUCTNAME,
321 INSTALLPROPERTY_PRODUCTNAME,
322 INSTALLPROPERTY_PACKAGENAME,
323 };
324
325 wchar_t wszProductName[1024];
326 DWORD cwcProductName;
327 unsigned i = 0;
328 do
329 {
330 cwcProductName = RT_ELEMENTS(wszProductName) - 1;
331 uRc = pfnMsiGetProductPropertyW(hMsi, s_apwszProps[i], wszProductName, &cwcProductName);
332 }
333 while ( ++i < RT_ELEMENTS(s_apwszProps)
334 && ( uRc != 0
335 || cwcProductName < 2
336 || cwcProductName >= RT_ELEMENTS(wszProductName)) );
337 uRc = pfnMsiCloseHandle(hMsi);
338 if (uRc == 0 && cwcProductName >= 2)
339 {
340 wszProductName[RT_MIN(cwcProductName, RT_ELEMENTS(wszProductName) - 1)] = '\0';
341 setError(hrcCaller,
342 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
343 "PSDispatch looks broken by the '%ls' (%ls) program, suspecting that it features the broken oleaut32.msm module as component %ls.\n"
344 "\n"
345 "We suggest you try uninstall '%ls'.\n"
346 "\n"
347 "See also https://support.microsoft.com/en-us/kb/316911 "),
348 wszProductName, wszProductCode, wszComponentCode, wszProductName);
349 fSetError = true;
350 }
351 }
352 }
353
354 /* MSI uses COM and may mess up our stuff. So, we wait with the fallback till afterwards in this case. */
355 if (!fSetError)
356 {
357 setError(hrcCaller,
358 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
359 "PSDispatch looks broken by installer %ls featuring the broken oleaut32.msm module as component %ls.\n"
360 "\n"
361 "See also https://support.microsoft.com/en-us/kb/316911 "),
362 wszProductCode, wszComponentCode);
363 fSetError = true;
364 }
365 }
366 }
367 if (!fSetError)
368 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
369 "PSDispatch looks broken by some installer featuring the broken oleaut32.msm module as a component.\n"
370 "\n"
371 "See also https://support.microsoft.com/en-us/kb/316911 "));
372 }
373 else if (lrc == ERROR_FILE_NOT_FOUND)
374 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
375 "PSDispatch looks fine. Weird"));
376 else
377 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
378 "Checking out PSDispatch registration ended with error: %u (%#x)"), lrc, lrc);
379 RegCloseKey(hKey);
380 }
381
382 pUnknown->Release();
383 return hrcCaller;
384}
385
386# ifdef VBOX_WITH_SDS
387/**
388 * Gets the service account name and start type for the given service.
389 *
390 * @returns IPRT status code (for some reason).
391 * @param pwszServiceName The name of the service.
392 * @param pwszAccountName Where to return the account name.
393 * @param cwcAccountName The length of the account name buffer (in WCHARs).
394 * @param puStartType Where to return the start type.
395 */
396int VirtualBoxClient::i_getServiceAccountAndStartType(const wchar_t *pwszServiceName,
397 wchar_t *pwszAccountName, size_t cwcAccountName, uint32_t *puStartType)
398{
399 AssertPtr(pwszServiceName);
400 AssertPtr(pwszAccountName);
401 Assert(cwcAccountName);
402 *pwszAccountName = '\0';
403 *puStartType = SERVICE_DEMAND_START;
404
405 int vrc;
406
407 // Get a handle to the SCM database.
408 SC_HANDLE hSCManager = OpenSCManagerW(NULL /*pwszMachineName*/, NULL /*pwszDatabaseName*/, SC_MANAGER_CONNECT);
409 if (hSCManager != NULL)
410 {
411 SC_HANDLE hService = OpenServiceW(hSCManager, pwszServiceName, SERVICE_QUERY_CONFIG);
412 if (hService != NULL)
413 {
414 DWORD cbNeeded = sizeof(QUERY_SERVICE_CONFIGW) + _1K;
415 if (!QueryServiceConfigW(hService, NULL, 0, &cbNeeded))
416 {
417 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
418 LPQUERY_SERVICE_CONFIGW pSc = (LPQUERY_SERVICE_CONFIGW)RTMemTmpAllocZ(cbNeeded + _1K);
419 if (pSc)
420 {
421 DWORD cbNeeded2 = 0;
422 if (QueryServiceConfigW(hService, pSc, cbNeeded + _1K, &cbNeeded2))
423 {
424 *puStartType = pSc->dwStartType;
425 vrc = RTUtf16Copy(pwszAccountName, cwcAccountName, pSc->lpServiceStartName);
426 if (RT_FAILURE(vrc))
427 LogRel(("Error: SDS service name is too long (%Rrc): %ls\n", vrc, pSc->lpServiceStartName));
428 }
429 else
430 {
431 int dwError = GetLastError();
432 vrc = RTErrConvertFromWin32(dwError);
433 LogRel(("Error: Failed querying '%ls' service config: %Rwc (%u) -> %Rrc; cbNeeded=%d cbNeeded2=%d\n",
434 pwszServiceName, dwError, dwError, vrc, cbNeeded, cbNeeded2));
435 }
436 RTMemTmpFree(pSc);
437 }
438 else
439 {
440 LogRel(("Error: Failed allocating %#x bytes of memory for service config!\n", cbNeeded + _1K));
441 vrc = VERR_NO_TMP_MEMORY;
442 }
443 }
444 else
445 {
446 AssertLogRelMsgFailed(("Error: QueryServiceConfigW returns success with zero buffer!\n"));
447 vrc = VERR_IPE_UNEXPECTED_STATUS;
448 }
449 CloseServiceHandle(hService);
450 }
451 else
452 {
453 int dwError = GetLastError();
454 vrc = RTErrConvertFromWin32(dwError);
455 LogRel(("Error: Could not open service '%ls': %Rwc (%u) -> %Rrc\n", pwszServiceName, dwError, dwError, vrc));
456 }
457 CloseServiceHandle(hSCManager);
458 }
459 else
460 {
461 int dwError = GetLastError();
462 vrc = RTErrConvertFromWin32(dwError);
463 LogRel(("Error: Could not open SCM: %Rwc (%u) -> %Rrc\n", dwError, dwError, vrc));
464 }
465 return vrc;
466}
467# endif /* VBOX_WITH_SDS */
468
469#endif /* RT_OS_WINDOWS */
470
471/**
472 * Uninitializes the instance and sets the ready flag to FALSE.
473 * Called either from FinalRelease() or by the parent when it gets destroyed.
474 */
475void VirtualBoxClient::uninit()
476{
477 LogFlowThisFunc(("\n"));
478
479 /* Enclose the state transition Ready->InUninit->NotReady */
480 AutoUninitSpan autoUninitSpan(this);
481 if (autoUninitSpan.uninitDone())
482 return;
483
484 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
485 {
486 /* Signal the event semaphore and wait for the thread to terminate.
487 * if it hangs for some reason exit anyway, this can cause a crash
488 * though as the object will no longer be available. */
489 RTSemEventSignal(mData.m_SemEvWatcher);
490 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
491 mData.m_ThreadWatcher = NIL_RTTHREAD;
492 RTSemEventDestroy(mData.m_SemEvWatcher);
493 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
494 }
495
496 mData.m_pToken.setNull();
497 mData.m_pVirtualBox.setNull();
498
499 ASMAtomicDecU32(&g_cInstances);
500}
501
502// IVirtualBoxClient properties
503/////////////////////////////////////////////////////////////////////////////
504
505/**
506 * Returns a reference to the VirtualBox object.
507 *
508 * @returns COM status code
509 * @param aVirtualBox Address of result variable.
510 */
511HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
512{
513 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
514 aVirtualBox = mData.m_pVirtualBox;
515 return S_OK;
516}
517
518/**
519 * Create a new Session object and return a reference to it.
520 *
521 * @returns COM status code
522 * @param aSession Address of result variable.
523 */
524HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
525{
526 /* this is not stored in this object, no need to lock */
527 ComPtr<ISession> pSession;
528 HRESULT rc = pSession.createInprocObject(CLSID_Session);
529 if (SUCCEEDED(rc))
530 aSession = pSession;
531 return rc;
532}
533
534/**
535 * Return reference to the EventSource associated with this object.
536 *
537 * @returns COM status code
538 * @param aEventSource Address of result variable.
539 */
540HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
541{
542 /* this is const, no need to lock */
543 aEventSource = mData.m_pEventSource;
544 return aEventSource.isNull() ? E_FAIL : S_OK;
545}
546
547// IVirtualBoxClient methods
548/////////////////////////////////////////////////////////////////////////////
549
550/**
551 * Checks a Machine object for any pending errors.
552 *
553 * @returns COM status code
554 * @param aMachine Machine object to check.
555 */
556HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
557{
558 BOOL fAccessible = FALSE;
559 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
560 if (FAILED(rc))
561 return setError(rc, tr("Could not check the accessibility status of the VM"));
562 else if (!fAccessible)
563 {
564 ComPtr<IVirtualBoxErrorInfo> pAccessError;
565 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
566 if (FAILED(rc))
567 return setError(rc, tr("Could not get the access error message of the VM"));
568 else
569 {
570 ErrorInfo info(pAccessError);
571 ErrorInfoKeeper eik(info);
572 return info.getResultCode();
573 }
574 }
575 return S_OK;
576}
577
578// private methods
579/////////////////////////////////////////////////////////////////////////////
580
581
582/// @todo AM Add pinging of VBoxSDS
583/*static*/
584DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
585 void *pvUser)
586{
587 NOREF(ThreadSelf);
588 Assert(pvUser);
589 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
590 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
591 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
592 int vrc;
593
594 /* The likelihood of early crashes are high, so start with a short wait. */
595 vrc = RTSemEventWait(sem, cMillies / 2);
596
597 /* As long as the waiting times out keep retrying the wait. */
598 while (RT_FAILURE(vrc))
599 {
600 {
601 HRESULT rc = S_OK;
602 ComPtr<IVirtualBox> pV;
603 {
604 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
605 pV = pThis->mData.m_pVirtualBox;
606 }
607 if (!pV.isNull())
608 {
609 ULONG rev;
610 rc = pV->COMGETTER(Revision)(&rev);
611 if (FAILED_DEAD_INTERFACE(rc))
612 {
613 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
614 {
615 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
616 /* Throw away the VirtualBox reference, it's no longer
617 * usable as VBoxSVC terminated in the mean time. */
618 pThis->mData.m_pVirtualBox.setNull();
619 }
620 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
621 }
622 }
623 else
624 {
625 /* Try to get a new VirtualBox reference straight away, and if
626 * this fails use an increased waiting time as very frequent
627 * restart attempts in some wedged config can cause high CPU
628 * and disk load. */
629 ComPtr<IVirtualBox> pVirtualBox;
630 ComPtr<IToken> pToken;
631 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
632 if (FAILED(rc))
633 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
634 else
635 {
636 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
637 {
638 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
639 /* Update the VirtualBox reference, there's a working
640 * VBoxSVC again from now on. */
641 pThis->mData.m_pVirtualBox = pVirtualBox;
642 pThis->mData.m_pToken = pToken;
643 }
644 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
645 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
646 }
647 }
648 }
649 vrc = RTSemEventWait(sem, cMillies);
650 }
651 return 0;
652}
653
654/* 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