VirtualBox

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

Last change on this file since 86506 was 85489, checked in by vboxsync, 4 years ago

Main: bugref:9784: Moved the call to CoInitializeSecurity into com::Initialize from UICommon.cpp and VirtualBoxClientImpl.cpp

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

© 2023 Oracle
ContactPrivacy policyTerms of Use