VirtualBox

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

Last change on this file since 70063 was 69806, checked in by vboxsync, 7 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. [doxygen]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.1 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 69806 2017-11-22 12:20:54Z 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.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/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 can 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
379/**
380 * Gets the service account name and start type for the given service.
381 *
382 * @returns IPRT status code (for some reason).
383 * @param pwszServiceName The name of the service.
384 * @param pwszAccountName Where to return the account name.
385 * @param cwcAccountName The length of the account name buffer (in WCHARs).
386 * @param puStartType Where to return the start type.
387 */
388int VirtualBoxClient::i_getServiceAccountAndStartType(const wchar_t *pwszServiceName,
389 wchar_t *pwszAccountName, size_t cwcAccountName, uint32_t *puStartType)
390{
391 AssertPtr(pwszServiceName);
392 AssertPtr(pwszAccountName);
393 Assert(cwcAccountName);
394 *pwszAccountName = '\0';
395 *puStartType = SERVICE_DEMAND_START;
396
397 int vrc;
398
399 // Get a handle to the SCM database.
400 SC_HANDLE hSCManager = OpenSCManagerW(NULL /*pwszMachineName*/, NULL /*pwszDatabaseName*/, SC_MANAGER_CONNECT);
401 if (hSCManager != NULL)
402 {
403 SC_HANDLE hService = OpenServiceW(hSCManager, pwszServiceName, SERVICE_QUERY_CONFIG);
404 if (hService != NULL)
405 {
406 DWORD cbNeeded = sizeof(QUERY_SERVICE_CONFIGW) + _1K;
407 if (!QueryServiceConfigW(hService, NULL, 0, &cbNeeded))
408 {
409 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
410 LPQUERY_SERVICE_CONFIGW pSc = (LPQUERY_SERVICE_CONFIGW)RTMemTmpAllocZ(cbNeeded + _1K);
411 if (pSc)
412 {
413 DWORD cbNeeded2 = 0;
414 if (QueryServiceConfigW(hService, pSc, cbNeeded + _1K, &cbNeeded2))
415 {
416 *puStartType = pSc->dwStartType;
417 vrc = RTUtf16Copy(pwszAccountName, cwcAccountName, pSc->lpServiceStartName);
418 if (RT_FAILURE(vrc))
419 LogRel(("Error: SDS service name is too long (%Rrc): %ls\n", vrc, pSc->lpServiceStartName));
420 }
421 else
422 {
423 int dwError = GetLastError();
424 vrc = RTErrConvertFromWin32(dwError);
425 LogRel(("Error: Failed querying service config: %Rwc (%u) -> %Rrc; cbNeeded=%d cbNeeded2=%d\n",
426 dwError, dwError, vrc, cbNeeded, cbNeeded2));
427 }
428 RTMemTmpFree(pSc);
429 }
430 else
431 {
432 LogRel(("Error: Failed allocating %#x bytes of memory for service config!\n", cbNeeded + _1K));
433 vrc = VERR_NO_TMP_MEMORY;
434 }
435 }
436 else
437 {
438 AssertLogRelMsgFailed(("Error: QueryServiceConfigW returns success with zero buffer!\n"));
439 vrc = VERR_IPE_UNEXPECTED_STATUS;
440 }
441 CloseServiceHandle(hService);
442 }
443 else
444 {
445 int dwError = GetLastError();
446 vrc = RTErrConvertFromWin32(dwError);
447 LogRel(("Error: Could not open service: %Rwc (%u) -> %Rrc\n", dwError, dwError, vrc));
448 }
449 CloseServiceHandle(hSCManager);
450 }
451 else
452 {
453 int dwError = GetLastError();
454 vrc = RTErrConvertFromWin32(dwError);
455 LogRel(("Error: Could not open SCM: %Rwc (%u) -> %Rrc\n", dwError, dwError, vrc));
456 }
457 return vrc;
458}
459# endif /* VBOX_WITH_SDS */
460
461#endif /* RT_OS_WINDOWS */
462
463/**
464 * Uninitializes the instance and sets the ready flag to FALSE.
465 * Called either from FinalRelease() or by the parent when it gets destroyed.
466 */
467void VirtualBoxClient::uninit()
468{
469 LogFlowThisFunc(("\n"));
470
471 /* Enclose the state transition Ready->InUninit->NotReady */
472 AutoUninitSpan autoUninitSpan(this);
473 if (autoUninitSpan.uninitDone())
474 return;
475
476 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
477 {
478 /* Signal the event semaphore and wait for the thread to terminate.
479 * if it hangs for some reason exit anyway, this can cause a crash
480 * though as the object will no longer be available. */
481 RTSemEventSignal(mData.m_SemEvWatcher);
482 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
483 mData.m_ThreadWatcher = NIL_RTTHREAD;
484 RTSemEventDestroy(mData.m_SemEvWatcher);
485 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
486 }
487
488 mData.m_pToken.setNull();
489 mData.m_pVirtualBox.setNull();
490
491 ASMAtomicDecU32(&g_cInstances);
492}
493
494// IVirtualBoxClient properties
495/////////////////////////////////////////////////////////////////////////////
496
497/**
498 * Returns a reference to the VirtualBox object.
499 *
500 * @returns COM status code
501 * @param aVirtualBox Address of result variable.
502 */
503HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
504{
505 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
506 aVirtualBox = mData.m_pVirtualBox;
507 return S_OK;
508}
509
510/**
511 * Create a new Session object and return a reference to it.
512 *
513 * @returns COM status code
514 * @param aSession Address of result variable.
515 */
516HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
517{
518 /* this is not stored in this object, no need to lock */
519 ComPtr<ISession> pSession;
520 HRESULT rc = pSession.createInprocObject(CLSID_Session);
521 if (SUCCEEDED(rc))
522 aSession = pSession;
523 return rc;
524}
525
526/**
527 * Return reference to the EventSource associated with this object.
528 *
529 * @returns COM status code
530 * @param aEventSource Address of result variable.
531 */
532HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
533{
534 /* this is const, no need to lock */
535 aEventSource = mData.m_pEventSource;
536 return aEventSource.isNull() ? E_FAIL : S_OK;
537}
538
539// IVirtualBoxClient methods
540/////////////////////////////////////////////////////////////////////////////
541
542/**
543 * Checks a Machine object for any pending errors.
544 *
545 * @returns COM status code
546 * @param aMachine Machine object to check.
547 */
548HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
549{
550 BOOL fAccessible = FALSE;
551 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
552 if (FAILED(rc))
553 return setError(rc, tr("Could not check the accessibility status of the VM"));
554 else if (!fAccessible)
555 {
556 ComPtr<IVirtualBoxErrorInfo> pAccessError;
557 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
558 if (FAILED(rc))
559 return setError(rc, tr("Could not get the access error message of the VM"));
560 else
561 {
562 ErrorInfo info(pAccessError);
563 ErrorInfoKeeper eik(info);
564 return info.getResultCode();
565 }
566 }
567 return S_OK;
568}
569
570// private methods
571/////////////////////////////////////////////////////////////////////////////
572
573
574/// @todo AM Add pinging of VBoxSDS
575/*static*/
576DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
577 void *pvUser)
578{
579 NOREF(ThreadSelf);
580 Assert(pvUser);
581 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
582 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
583 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
584 int vrc;
585
586 /* The likelihood of early crashes are high, so start with a short wait. */
587 vrc = RTSemEventWait(sem, cMillies / 2);
588
589 /* As long as the waiting times out keep retrying the wait. */
590 while (RT_FAILURE(vrc))
591 {
592 {
593 HRESULT rc = S_OK;
594 ComPtr<IVirtualBox> pV;
595 {
596 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
597 pV = pThis->mData.m_pVirtualBox;
598 }
599 if (!pV.isNull())
600 {
601 ULONG rev;
602 rc = pV->COMGETTER(Revision)(&rev);
603 if (FAILED_DEAD_INTERFACE(rc))
604 {
605 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
606 {
607 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
608 /* Throw away the VirtualBox reference, it's no longer
609 * usable as VBoxSVC terminated in the mean time. */
610 pThis->mData.m_pVirtualBox.setNull();
611 }
612 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
613 }
614 }
615 else
616 {
617 /* Try to get a new VirtualBox reference straight away, and if
618 * this fails use an increased waiting time as very frequent
619 * restart attempts in some wedged config can cause high CPU
620 * and disk load. */
621 ComPtr<IVirtualBox> pVirtualBox;
622 ComPtr<IToken> pToken;
623 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
624 if (FAILED(rc))
625 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
626 else
627 {
628 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
629 {
630 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
631 /* Update the VirtualBox reference, there's a working
632 * VBoxSVC again from now on. */
633 pThis->mData.m_pVirtualBox = pVirtualBox;
634 pThis->mData.m_pToken = pToken;
635 }
636 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
637 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
638 }
639 }
640 }
641 vrc = RTSemEventWait(sem, cMillies);
642 }
643 return 0;
644}
645
646/* 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