VirtualBox

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

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

VirtualBoxClient: brought back some problem determination code useful for i_investigateVirtualBoxObjectCreationFailure, adjusting it a bit. (Untested as I'm on darwin host right now.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.5 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 69791 2017-11-21 13:54:53Z 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# ifdef VBOX_WITH_SDS
194 /*
195 * Check that the VBoxSDS service is configured to run as LocalSystem and is enabled.
196 */
197 WCHAR wszBuffer[256];
198 int vrc = i_getServiceAccount(L"VBoxSDS", wszBuffer, RT_ELEMENTS(wszBuffer));
199 if (RT_SUCCESS(vrc))
200 {
201 LogRelFunc(("VBoxSDS service is running under the '%ls' account.\n", wszBuffer));
202 if (RTUtf16Cmp(wszBuffer, L"LocalSystem") != 0)
203 return setError(hrcCaller,
204 tr("VBoxSDS should be run under SYSTEM account, but it started under '%ls' account:\n"
205 "Change VBoxSDS Windows Service Logon parameters in Service Control Manager. \n%Rhrc"),
206 wszBuffer, hrcCaller);
207 }
208 else
209 LogRelFunc(("VirtualBoxClient::i_getServiceAccount failed: %Rrc\n", vrc));
210
211 bool fIsVBoxSDSDisabled = false;
212 HRESULT hrc = i_isServiceDisabled(L"VBoxSDS", &fIsVBoxSDSDisabled);
213 if (SUCCEEDED(hrc) && fIsVBoxSDSDisabled)
214 return setError(hrcCaller,
215 tr("The VBoxSDS windows service is disabled.\n"
216 "Enable VBoxSDS Windows Service using Windows Service Management Console.\n %Rhrc"), hrcCaller);
217 if (FAILED(hrc))
218 LogRelFunc(("Warning: Failed to get information about VBoxSDS using WMI:: %Rhrc", hrc));
219# endif /* VBOX_WITH_SDS */
220
221 /*
222 * First step is to try get an IUnknown interface of the VirtualBox object.
223 *
224 * This will succeed even when oleaut32.msm (see @bugref{8016}, @ticketref{12087})
225 * is accidentally installed and messes up COM. It may also succeed when the COM
226 * registration is partially broken (though that's unlikely to happen these days).
227 */
228 IUnknown *pUnknown = NULL;
229 HRESULT hrc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
230 if (FAILED(hrc))
231 {
232 if (hrc == hrcCaller)
233 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc"), hrcCaller);
234 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc & %Rhrc"), hrcCaller, hrc);
235 }
236
237 /*
238 * Try query the IVirtualBox interface (should fail), if it succeed we return
239 * straight away so we have more columns to spend on long messages below.
240 */
241 IVirtualBox *pVirtualBox;
242 hrc = pUnknown->QueryInterface(IID_IVirtualBox, (void **)&pVirtualBox);
243 if (SUCCEEDED(hrc))
244 {
245 pVirtualBox->Release();
246 pUnknown->Release();
247 return setError(hrcCaller,
248 tr("Failed to instantiate CLSID_VirtualBox the first time, but worked when checking out why ... weird"));
249 }
250
251 /*
252 * Check for oleaut32.msm traces in the registry.
253 */
254 HKEY hKey;
255 LSTATUS lrc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer32",
256 0 /*fFlags*/, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | STANDARD_RIGHTS_READ, &hKey);
257 if (lrc == ERROR_SUCCESS)
258 {
259 wchar_t wszBuf[8192];
260 DWORD cbBuf = sizeof(wszBuf) - sizeof(wchar_t);
261 DWORD dwType = 0;
262 lrc = RegQueryValueExW(hKey, L"InprocServer32", NULL /*pvReserved*/, &dwType, (BYTE *)&wszBuf[0], &cbBuf);
263 if (lrc == ERROR_SUCCESS)
264 {
265 wszBuf[cbBuf / sizeof(wchar_t)] = '\0';
266 bool fSetError = false;
267
268 /*
269 * Try decode the string and improve the message.
270 */
271 typedef UINT (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor,
272 LPWSTR pwszProductCode /*[40]*/,
273 LPWSTR pwszFeatureId /*[40]*/,
274 LPWSTR pwszComponentCode /*[40]*/,
275 DWORD *poffArguments);
276 PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW;
277 pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)RTLdrGetSystemSymbol("msi.dll", "MsiDecomposeDescriptorW");
278 if ( pfnMsiDecomposeDescriptorW
279 && ( dwType == REG_SZ
280 || dwType == REG_MULTI_SZ))
281 {
282 wchar_t wszProductCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
283 wchar_t wszFeatureId[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
284 wchar_t wszComponentCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
285 DWORD offArguments = ~(DWORD)0;
286 UINT uRc = pfnMsiDecomposeDescriptorW(wszBuf, wszProductCode, wszFeatureId, wszComponentCode, &offArguments);
287 if (uRc == 0)
288 {
289 /*
290 * Can we resolve the product code into a name?
291 */
292 typedef UINT (WINAPI *PFNMSIOPENPRODUCTW)(PCWSTR, MSIHANDLE *);
293 PFNMSIOPENPRODUCTW pfnMsiOpenProductW;
294 pfnMsiOpenProductW = (PFNMSIOPENPRODUCTW)RTLdrGetSystemSymbol("msi.dll", "MsiOpenProductW");
295
296 typedef UINT (WINAPI *PFNMSICLOSEHANDLE)(MSIHANDLE);
297 PFNMSICLOSEHANDLE pfnMsiCloseHandle;
298 pfnMsiCloseHandle = (PFNMSICLOSEHANDLE)RTLdrGetSystemSymbol("msi.dll", "MsiCloseHandle");
299
300 typedef UINT (WINAPI *PFNGETPRODUCTPROPERTYW)(MSIHANDLE, PCWSTR, PWSTR, PDWORD);
301 PFNGETPRODUCTPROPERTYW pfnMsiGetProductPropertyW;
302 pfnMsiGetProductPropertyW = (PFNGETPRODUCTPROPERTYW)RTLdrGetSystemSymbol("msi.dll", "MsiGetProductPropertyW");
303 if ( pfnMsiGetProductPropertyW
304 && pfnMsiCloseHandle
305 && pfnMsiOpenProductW)
306 {
307 MSIHANDLE hMsi = 0;
308 uRc = pfnMsiOpenProductW(wszProductCode, &hMsi);
309 if (uRc == 0)
310 {
311 static wchar_t const * const s_apwszProps[] =
312 {
313 INSTALLPROPERTY_INSTALLEDPRODUCTNAME,
314 INSTALLPROPERTY_PRODUCTNAME,
315 INSTALLPROPERTY_PACKAGENAME,
316 };
317
318 wchar_t wszProductName[1024];
319 DWORD cwcProductName;
320 unsigned i = 0;
321 do
322 {
323 cwcProductName = RT_ELEMENTS(wszProductName) - 1;
324 uRc = pfnMsiGetProductPropertyW(hMsi, s_apwszProps[i], wszProductName, &cwcProductName);
325 }
326 while ( ++i < RT_ELEMENTS(s_apwszProps)
327 && ( uRc != 0
328 || cwcProductName < 2
329 || cwcProductName >= RT_ELEMENTS(wszProductName)) );
330 uRc = pfnMsiCloseHandle(hMsi);
331 if (uRc == 0 && cwcProductName >= 2)
332 {
333 wszProductName[RT_MIN(cwcProductName, RT_ELEMENTS(wszProductName) - 1)] = '\0';
334 setError(hrcCaller,
335 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
336 "PSDispatch looks broken by the '%ls' (%ls) program, suspecting that it features the broken oleaut32.msm module as component %ls.\n"
337 "\n"
338 "We suggest you try uninstall '%ls'.\n"
339 "\n"
340 "See also https://support.microsoft.com/en-us/kb/316911 "),
341 wszProductName, wszProductCode, wszComponentCode, wszProductName);
342 fSetError = true;
343 }
344 }
345 }
346
347 /* MSI uses COM and may mess up our stuff. So, we wait with the fallback till afterwards in this case. */
348 if (!fSetError)
349 {
350 setError(hrcCaller,
351 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
352 "PSDispatch looks broken by installer %ls featuring the broken oleaut32.msm module as component %ls.\n"
353 "\n"
354 "See also https://support.microsoft.com/en-us/kb/316911 "),
355 wszProductCode, wszComponentCode);
356 fSetError = true;
357 }
358 }
359 }
360 if (!fSetError)
361 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
362 "PSDispatch looks broken by some installer featuring the broken oleaut32.msm module as a component.\n"
363 "\n"
364 "See also https://support.microsoft.com/en-us/kb/316911 "));
365 }
366 else if (lrc == ERROR_FILE_NOT_FOUND)
367 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
368 "PSDispatch looks fine. Weird"));
369 else
370 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
371 "Checking out PSDispatch registration ended with error: %u (%#x)"), lrc, lrc);
372 RegCloseKey(hKey);
373 }
374
375 pUnknown->Release();
376 return hrcCaller;
377}
378
379# ifdef VBOX_WITH_SDS
380
381int VirtualBoxClient::i_getServiceAccount(const wchar_t *pwszServiceName, wchar_t *pwszAccountName, size_t cwcAccountName)
382{
383 AssertPtr(pwszServiceName);
384 AssertPtr(pwszAccountName);
385 Assert(cwcAccountName);
386 *pwszAccountName = '\0';
387
388 int vrc;
389
390 // Get a handle to the SCM database.
391 SC_HANDLE hSCManager = OpenSCManagerW(NULL /*pwszMachineName*/, NULL /*pwszDatabaseName*/, SC_MANAGER_ALL_ACCESS);
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);
402 if (pSc)
403 {
404 DWORD cbNeeded2 = 0;
405 if (QueryServiceConfigW(hService, pSc, cbNeeded, &cbNeeded2))
406 {
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 service config: %Rwc (%u) -> %Rrc; cbNeeded=%d cbNeeded2=%d\n",
416 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));
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: %Rwc (%u) -> %Rrc\n", 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
450
451HRESULT VirtualBoxClient::i_isServiceDisabled(const wchar_t *pwszServiceName, bool* pfOutIsDisabled)
452{
453 /** @todo r=bird: there must be a way we can get this information from the
454 * service manager. This is overly complicated. */
455 AssertPtr(pwszServiceName);
456 AssertPtr(pfOutIsDisabled);
457 *pfOutIsDisabled = false;
458
459 ComPtr<IWbemLocator> aLocator;
460 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void **)aLocator.asOutParam());
461 if (FAILED(hr))
462 {
463 LogRel(("Error: Cannot instantiate WbemLocator: %Rhrc", hr));
464 return hr;
465 }
466
467 ComPtr<IWbemServices> aService;
468 hr = aLocator->ConnectServer(com::Bstr(L"ROOT\\CIMV2").raw(), // Object path of WMI namespace
469 NULL, // User name. NULL = current user
470 NULL, // User password. NULL = current
471 0, // Locale. NULL indicates current
472 NULL, // Security flags.
473 0, // Authority (for example, Kerberos)
474 0, // Context object
475 aService.asOutParam()); // pointer to IWbemServices proxy
476 if (FAILED(hr))
477 {
478 LogRel(("Error: Cannot connect to Wbem Service: %Rhrc\n", hr));
479 return hr;
480 }
481
482 // query settings for VBoxSDS windows service
483 ComPtr<IEnumWbemClassObject> aEnumerator;
484 hr = aService->ExecQuery(com::Bstr("WQL").raw(),
485 com::BstrFmt("SELECT * FROM Win32_Service WHERE Name='%ls'", pwszServiceName).raw(),
486 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
487 NULL,
488 aEnumerator.asOutParam());
489 if (FAILED(hr) || aEnumerator == NULL)
490 {
491 LogRel(("Error: querying service settings from WMI: %Rhrc\n", hr));
492 return hr;
493 }
494
495 ULONG uReturn = 0;
496 ComPtr<IWbemClassObject> aVBoxSDSObj;
497 hr = aEnumerator->Next(WBEM_INFINITE, 1, aVBoxSDSObj.asOutParam(), &uReturn);
498 if (FAILED(hr))
499 {
500 LogRel(("Error: Cannot get Service WMI record: %Rhrc\n", hr));
501 return hr;
502 }
503 if (aVBoxSDSObj == NULL || uReturn == 0)
504 {
505 LogRel(("Error: Service record didn't exist in WMI: %Rhrc\n", hr));
506 return hr;
507 }
508
509 // Get "StartMode" property
510 VARIANT vtProp;
511 VariantInit(&vtProp);
512 hr = aVBoxSDSObj->Get(L"StartMode", 0, &vtProp, 0, 0);
513 if (FAILED(hr) || (vtProp.vt & VT_NULL) == VT_NULL)
514 {
515 LogRel(("Error: Didn't found StartMode property: %Rhrc\n", hr));
516 return hr;
517 }
518
519 Assert((vtProp.vt & VT_BSTR) == VT_BSTR);
520
521 *pfOutIsDisabled = RTUtf16Cmp((RTUTF16*)vtProp.bstrVal, (RTUTF16*)L"Disabled") == 0;
522
523 LogRel(("Service start mode is '%ls' \n", vtProp.bstrVal));
524 VariantClear(&vtProp);
525 return S_OK;
526}
527
528# endif /* VBOX_WITH_SDS */
529
530#endif /* RT_OS_WINDOWS */
531
532/**
533 * Uninitializes the instance and sets the ready flag to FALSE.
534 * Called either from FinalRelease() or by the parent when it gets destroyed.
535 */
536void VirtualBoxClient::uninit()
537{
538 LogFlowThisFunc(("\n"));
539
540 /* Enclose the state transition Ready->InUninit->NotReady */
541 AutoUninitSpan autoUninitSpan(this);
542 if (autoUninitSpan.uninitDone())
543 return;
544
545 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
546 {
547 /* Signal the event semaphore and wait for the thread to terminate.
548 * if it hangs for some reason exit anyway, this can cause a crash
549 * though as the object will no longer be available. */
550 RTSemEventSignal(mData.m_SemEvWatcher);
551 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
552 mData.m_ThreadWatcher = NIL_RTTHREAD;
553 RTSemEventDestroy(mData.m_SemEvWatcher);
554 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
555 }
556
557 mData.m_pToken.setNull();
558 mData.m_pVirtualBox.setNull();
559
560 ASMAtomicDecU32(&g_cInstances);
561}
562
563// IVirtualBoxClient properties
564/////////////////////////////////////////////////////////////////////////////
565
566/**
567 * Returns a reference to the VirtualBox object.
568 *
569 * @returns COM status code
570 * @param aVirtualBox Address of result variable.
571 */
572HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
573{
574 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
575 aVirtualBox = mData.m_pVirtualBox;
576 return S_OK;
577}
578
579/**
580 * Create a new Session object and return a reference to it.
581 *
582 * @returns COM status code
583 * @param aSession Address of result variable.
584 */
585HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
586{
587 /* this is not stored in this object, no need to lock */
588 ComPtr<ISession> pSession;
589 HRESULT rc = pSession.createInprocObject(CLSID_Session);
590 if (SUCCEEDED(rc))
591 aSession = pSession;
592 return rc;
593}
594
595/**
596 * Return reference to the EventSource associated with this object.
597 *
598 * @returns COM status code
599 * @param aEventSource Address of result variable.
600 */
601HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
602{
603 /* this is const, no need to lock */
604 aEventSource = mData.m_pEventSource;
605 return aEventSource.isNull() ? E_FAIL : S_OK;
606}
607
608// IVirtualBoxClient methods
609/////////////////////////////////////////////////////////////////////////////
610
611/**
612 * Checks a Machine object for any pending errors.
613 *
614 * @returns COM status code
615 * @param aMachine Machine object to check.
616 */
617HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
618{
619 BOOL fAccessible = FALSE;
620 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
621 if (FAILED(rc))
622 return setError(rc, tr("Could not check the accessibility status of the VM"));
623 else if (!fAccessible)
624 {
625 ComPtr<IVirtualBoxErrorInfo> pAccessError;
626 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
627 if (FAILED(rc))
628 return setError(rc, tr("Could not get the access error message of the VM"));
629 else
630 {
631 ErrorInfo info(pAccessError);
632 ErrorInfoKeeper eik(info);
633 return info.getResultCode();
634 }
635 }
636 return S_OK;
637}
638
639// private methods
640/////////////////////////////////////////////////////////////////////////////
641
642
643/// @todo AM Add pinging of VBoxSDS
644/*static*/
645DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
646 void *pvUser)
647{
648 NOREF(ThreadSelf);
649 Assert(pvUser);
650 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
651 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
652 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
653 int vrc;
654
655 /* The likelihood of early crashes are high, so start with a short wait. */
656 vrc = RTSemEventWait(sem, cMillies / 2);
657
658 /* As long as the waiting times out keep retrying the wait. */
659 while (RT_FAILURE(vrc))
660 {
661 {
662 HRESULT rc = S_OK;
663 ComPtr<IVirtualBox> pV;
664 {
665 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
666 pV = pThis->mData.m_pVirtualBox;
667 }
668 if (!pV.isNull())
669 {
670 ULONG rev;
671 rc = pV->COMGETTER(Revision)(&rev);
672 if (FAILED_DEAD_INTERFACE(rc))
673 {
674 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
675 {
676 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
677 /* Throw away the VirtualBox reference, it's no longer
678 * usable as VBoxSVC terminated in the mean time. */
679 pThis->mData.m_pVirtualBox.setNull();
680 }
681 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
682 }
683 }
684 else
685 {
686 /* Try to get a new VirtualBox reference straight away, and if
687 * this fails use an increased waiting time as very frequent
688 * restart attempts in some wedged config can cause high CPU
689 * and disk load. */
690 ComPtr<IVirtualBox> pVirtualBox;
691 ComPtr<IToken> pToken;
692 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
693 if (FAILED(rc))
694 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
695 else
696 {
697 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
698 {
699 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
700 /* Update the VirtualBox reference, there's a working
701 * VBoxSVC again from now on. */
702 pThis->mData.m_pVirtualBox = pVirtualBox;
703 pThis->mData.m_pToken = pToken;
704 }
705 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
706 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
707 }
708 }
709 }
710 vrc = RTSemEventWait(sem, cMillies);
711 }
712 return 0;
713}
714
715/* 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