VirtualBox

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

Last change on this file since 69804 was 69804, checked in by vboxsync, 8 years ago

VirtualBoxClient: Dropped the WMI non-sense to get service status, because the information is readily available in the structure with the service account from. Also, only request minimum SCM access rights when doing the query.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette