VirtualBox

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

Last change on this file since 70296 was 70296, checked in by vboxsync, 7 years ago

VBoxSDS: ​​​​bugref:3300: added error description if VBoxSDS deleted.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 70296 2017-12-21 22:55:06Z 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 {
218 if (vrc == VERR_NOT_FOUND)
219 {
220 return setError(hrcCaller,
221 tr("The VBoxSDS windows service doesn't exist, needs to reinstall it.\n"
222 "To do this, start VirtualBox as Administrator, this automatically reinstall the service,"
223 "or run 'VBoxSDS.exe --regservice' command from Administrator console."));
224 }
225 LogRelFunc(("VirtualBoxClient::i_getServiceAccount failed: %Rrc\n", vrc));
226 }
227# endif
228
229 /*
230 * First step is to try get an IUnknown interface of the VirtualBox object.
231 *
232 * This will succeed even when oleaut32.msm (see @bugref{8016}, @ticketref{12087})
233 * is accidentally installed and messes up COM. It may also succeed when the COM
234 * registration is partially broken (though that's unlikely to happen these days).
235 */
236 IUnknown *pUnknown = NULL;
237 hrc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
238 if (FAILED(hrc))
239 {
240 if (hrc == hrcCaller)
241 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc"), hrcCaller);
242 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc & %Rhrc"), hrcCaller, hrc);
243 }
244
245 /*
246 * Try query the IVirtualBox interface (should fail), if it succeed we return
247 * straight away so we have more columns to spend on long messages below.
248 */
249 IVirtualBox *pVirtualBox;
250 hrc = pUnknown->QueryInterface(IID_IVirtualBox, (void **)&pVirtualBox);
251 if (SUCCEEDED(hrc))
252 {
253 pVirtualBox->Release();
254 pUnknown->Release();
255 return setError(hrcCaller,
256 tr("Failed to instantiate CLSID_VirtualBox the first time, but worked when checking out why ... weird"));
257 }
258
259 /*
260 * Check for oleaut32.msm traces in the registry.
261 */
262 HKEY hKey;
263 LSTATUS lrc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer32",
264 0 /*fFlags*/, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | STANDARD_RIGHTS_READ, &hKey);
265 if (lrc == ERROR_SUCCESS)
266 {
267 wchar_t wszBuf[8192];
268 DWORD cbBuf = sizeof(wszBuf) - sizeof(wchar_t);
269 DWORD dwType = 0;
270 lrc = RegQueryValueExW(hKey, L"InprocServer32", NULL /*pvReserved*/, &dwType, (BYTE *)&wszBuf[0], &cbBuf);
271 if (lrc == ERROR_SUCCESS)
272 {
273 wszBuf[cbBuf / sizeof(wchar_t)] = '\0';
274 bool fSetError = false;
275
276 /*
277 * Try decode the string and improve the message.
278 */
279 typedef UINT (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor,
280 LPWSTR pwszProductCode /*[40]*/,
281 LPWSTR pwszFeatureId /*[40]*/,
282 LPWSTR pwszComponentCode /*[40]*/,
283 DWORD *poffArguments);
284 PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW;
285 pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)RTLdrGetSystemSymbol("msi.dll", "MsiDecomposeDescriptorW");
286 if ( pfnMsiDecomposeDescriptorW
287 && ( dwType == REG_SZ
288 || dwType == REG_MULTI_SZ))
289 {
290 wchar_t wszProductCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
291 wchar_t wszFeatureId[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
292 wchar_t wszComponentCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
293 DWORD offArguments = ~(DWORD)0;
294 UINT uRc = pfnMsiDecomposeDescriptorW(wszBuf, wszProductCode, wszFeatureId, wszComponentCode, &offArguments);
295 if (uRc == 0)
296 {
297 /*
298 * Can we resolve the product code into a name?
299 */
300 typedef UINT (WINAPI *PFNMSIOPENPRODUCTW)(PCWSTR, MSIHANDLE *);
301 PFNMSIOPENPRODUCTW pfnMsiOpenProductW;
302 pfnMsiOpenProductW = (PFNMSIOPENPRODUCTW)RTLdrGetSystemSymbol("msi.dll", "MsiOpenProductW");
303
304 typedef UINT (WINAPI *PFNMSICLOSEHANDLE)(MSIHANDLE);
305 PFNMSICLOSEHANDLE pfnMsiCloseHandle;
306 pfnMsiCloseHandle = (PFNMSICLOSEHANDLE)RTLdrGetSystemSymbol("msi.dll", "MsiCloseHandle");
307
308 typedef UINT (WINAPI *PFNGETPRODUCTPROPERTYW)(MSIHANDLE, PCWSTR, PWSTR, PDWORD);
309 PFNGETPRODUCTPROPERTYW pfnMsiGetProductPropertyW;
310 pfnMsiGetProductPropertyW = (PFNGETPRODUCTPROPERTYW)RTLdrGetSystemSymbol("msi.dll", "MsiGetProductPropertyW");
311 if ( pfnMsiGetProductPropertyW
312 && pfnMsiCloseHandle
313 && pfnMsiOpenProductW)
314 {
315 MSIHANDLE hMsi = 0;
316 uRc = pfnMsiOpenProductW(wszProductCode, &hMsi);
317 if (uRc == 0)
318 {
319 static wchar_t const * const s_apwszProps[] =
320 {
321 INSTALLPROPERTY_INSTALLEDPRODUCTNAME,
322 INSTALLPROPERTY_PRODUCTNAME,
323 INSTALLPROPERTY_PACKAGENAME,
324 };
325
326 wchar_t wszProductName[1024];
327 DWORD cwcProductName;
328 unsigned i = 0;
329 do
330 {
331 cwcProductName = RT_ELEMENTS(wszProductName) - 1;
332 uRc = pfnMsiGetProductPropertyW(hMsi, s_apwszProps[i], wszProductName, &cwcProductName);
333 }
334 while ( ++i < RT_ELEMENTS(s_apwszProps)
335 && ( uRc != 0
336 || cwcProductName < 2
337 || cwcProductName >= RT_ELEMENTS(wszProductName)) );
338 uRc = pfnMsiCloseHandle(hMsi);
339 if (uRc == 0 && cwcProductName >= 2)
340 {
341 wszProductName[RT_MIN(cwcProductName, RT_ELEMENTS(wszProductName) - 1)] = '\0';
342 setError(hrcCaller,
343 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
344 "PSDispatch looks broken by the '%ls' (%ls) program, suspecting that it features the broken oleaut32.msm module as component %ls.\n"
345 "\n"
346 "We suggest you try uninstall '%ls'.\n"
347 "\n"
348 "See also https://support.microsoft.com/en-us/kb/316911 "),
349 wszProductName, wszProductCode, wszComponentCode, wszProductName);
350 fSetError = true;
351 }
352 }
353 }
354
355 /* MSI uses COM and may mess up our stuff. So, we wait with the fallback till afterwards in this case. */
356 if (!fSetError)
357 {
358 setError(hrcCaller,
359 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
360 "PSDispatch looks broken by installer %ls featuring the broken oleaut32.msm module as component %ls.\n"
361 "\n"
362 "See also https://support.microsoft.com/en-us/kb/316911 "),
363 wszProductCode, wszComponentCode);
364 fSetError = true;
365 }
366 }
367 }
368 if (!fSetError)
369 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
370 "PSDispatch looks broken by some installer featuring the broken oleaut32.msm module as a component.\n"
371 "\n"
372 "See also https://support.microsoft.com/en-us/kb/316911 "));
373 }
374 else if (lrc == ERROR_FILE_NOT_FOUND)
375 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
376 "PSDispatch looks fine. Weird"));
377 else
378 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
379 "Checking out PSDispatch registration ended with error: %u (%#x)"), lrc, lrc);
380 RegCloseKey(hKey);
381 }
382
383 pUnknown->Release();
384 return hrcCaller;
385}
386
387# ifdef VBOX_WITH_SDS
388/**
389 * Gets the service account name and start type for the given service.
390 *
391 * @returns IPRT status code (for some reason).
392 * @param pwszServiceName The name of the service.
393 * @param pwszAccountName Where to return the account name.
394 * @param cwcAccountName The length of the account name buffer (in WCHARs).
395 * @param puStartType Where to return the start type.
396 */
397int VirtualBoxClient::i_getServiceAccountAndStartType(const wchar_t *pwszServiceName,
398 wchar_t *pwszAccountName, size_t cwcAccountName, uint32_t *puStartType)
399{
400 AssertPtr(pwszServiceName);
401 AssertPtr(pwszAccountName);
402 Assert(cwcAccountName);
403 *pwszAccountName = '\0';
404 *puStartType = SERVICE_DEMAND_START;
405
406 int vrc;
407
408 // Get a handle to the SCM database.
409 SC_HANDLE hSCManager = OpenSCManagerW(NULL /*pwszMachineName*/, NULL /*pwszDatabaseName*/, SC_MANAGER_CONNECT);
410 if (hSCManager != NULL)
411 {
412 SC_HANDLE hService = OpenServiceW(hSCManager, pwszServiceName, SERVICE_QUERY_CONFIG);
413 if (hService != NULL)
414 {
415 DWORD cbNeeded = sizeof(QUERY_SERVICE_CONFIGW) + _1K;
416 if (!QueryServiceConfigW(hService, NULL, 0, &cbNeeded))
417 {
418 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
419 LPQUERY_SERVICE_CONFIGW pSc = (LPQUERY_SERVICE_CONFIGW)RTMemTmpAllocZ(cbNeeded + _1K);
420 if (pSc)
421 {
422 DWORD cbNeeded2 = 0;
423 if (QueryServiceConfigW(hService, pSc, cbNeeded + _1K, &cbNeeded2))
424 {
425 *puStartType = pSc->dwStartType;
426 vrc = RTUtf16Copy(pwszAccountName, cwcAccountName, pSc->lpServiceStartName);
427 if (RT_FAILURE(vrc))
428 LogRel(("Error: SDS service name is too long (%Rrc): %ls\n", vrc, pSc->lpServiceStartName));
429 }
430 else
431 {
432 int dwError = GetLastError();
433 vrc = RTErrConvertFromWin32(dwError);
434 LogRel(("Error: Failed querying '%ls' service config: %Rwc (%u) -> %Rrc; cbNeeded=%d cbNeeded2=%d\n",
435 pwszServiceName, dwError, dwError, vrc, cbNeeded, cbNeeded2));
436 }
437 RTMemTmpFree(pSc);
438 }
439 else
440 {
441 LogRel(("Error: Failed allocating %#x bytes of memory for service config!\n", cbNeeded + _1K));
442 vrc = VERR_NO_TMP_MEMORY;
443 }
444 }
445 else
446 {
447 AssertLogRelMsgFailed(("Error: QueryServiceConfigW returns success with zero buffer!\n"));
448 vrc = VERR_IPE_UNEXPECTED_STATUS;
449 }
450 CloseServiceHandle(hService);
451 }
452 else
453 {
454 int dwError = GetLastError();
455 vrc = RTErrConvertFromWin32(dwError);
456 LogRel(("Error: Could not open service '%ls': %Rwc (%u) -> %Rrc\n", pwszServiceName, dwError, dwError, vrc));
457 }
458 CloseServiceHandle(hSCManager);
459 }
460 else
461 {
462 int dwError = GetLastError();
463 vrc = RTErrConvertFromWin32(dwError);
464 LogRel(("Error: Could not open SCM: %Rwc (%u) -> %Rrc\n", dwError, dwError, vrc));
465 }
466 return vrc;
467}
468# endif /* VBOX_WITH_SDS */
469
470#endif /* RT_OS_WINDOWS */
471
472/**
473 * Uninitializes the instance and sets the ready flag to FALSE.
474 * Called either from FinalRelease() or by the parent when it gets destroyed.
475 */
476void VirtualBoxClient::uninit()
477{
478 LogFlowThisFunc(("\n"));
479
480 /* Enclose the state transition Ready->InUninit->NotReady */
481 AutoUninitSpan autoUninitSpan(this);
482 if (autoUninitSpan.uninitDone())
483 return;
484
485 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
486 {
487 /* Signal the event semaphore and wait for the thread to terminate.
488 * if it hangs for some reason exit anyway, this can cause a crash
489 * though as the object will no longer be available. */
490 RTSemEventSignal(mData.m_SemEvWatcher);
491 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
492 mData.m_ThreadWatcher = NIL_RTTHREAD;
493 RTSemEventDestroy(mData.m_SemEvWatcher);
494 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
495 }
496
497 mData.m_pToken.setNull();
498 mData.m_pVirtualBox.setNull();
499
500 ASMAtomicDecU32(&g_cInstances);
501}
502
503// IVirtualBoxClient properties
504/////////////////////////////////////////////////////////////////////////////
505
506/**
507 * Returns a reference to the VirtualBox object.
508 *
509 * @returns COM status code
510 * @param aVirtualBox Address of result variable.
511 */
512HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
513{
514 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
515 aVirtualBox = mData.m_pVirtualBox;
516 return S_OK;
517}
518
519/**
520 * Create a new Session object and return a reference to it.
521 *
522 * @returns COM status code
523 * @param aSession Address of result variable.
524 */
525HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
526{
527 /* this is not stored in this object, no need to lock */
528 ComPtr<ISession> pSession;
529 HRESULT rc = pSession.createInprocObject(CLSID_Session);
530 if (SUCCEEDED(rc))
531 aSession = pSession;
532 return rc;
533}
534
535/**
536 * Return reference to the EventSource associated with this object.
537 *
538 * @returns COM status code
539 * @param aEventSource Address of result variable.
540 */
541HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
542{
543 /* this is const, no need to lock */
544 aEventSource = mData.m_pEventSource;
545 return aEventSource.isNull() ? E_FAIL : S_OK;
546}
547
548// IVirtualBoxClient methods
549/////////////////////////////////////////////////////////////////////////////
550
551/**
552 * Checks a Machine object for any pending errors.
553 *
554 * @returns COM status code
555 * @param aMachine Machine object to check.
556 */
557HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
558{
559 BOOL fAccessible = FALSE;
560 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
561 if (FAILED(rc))
562 return setError(rc, tr("Could not check the accessibility status of the VM"));
563 else if (!fAccessible)
564 {
565 ComPtr<IVirtualBoxErrorInfo> pAccessError;
566 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
567 if (FAILED(rc))
568 return setError(rc, tr("Could not get the access error message of the VM"));
569 else
570 {
571 ErrorInfo info(pAccessError);
572 ErrorInfoKeeper eik(info);
573 return info.getResultCode();
574 }
575 }
576 return S_OK;
577}
578
579// private methods
580/////////////////////////////////////////////////////////////////////////////
581
582
583/// @todo AM Add pinging of VBoxSDS
584/*static*/
585DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
586 void *pvUser)
587{
588 NOREF(ThreadSelf);
589 Assert(pvUser);
590 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
591 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
592 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
593 int vrc;
594
595 /* The likelihood of early crashes are high, so start with a short wait. */
596 vrc = RTSemEventWait(sem, cMillies / 2);
597
598 /* As long as the waiting times out keep retrying the wait. */
599 while (RT_FAILURE(vrc))
600 {
601 {
602 HRESULT rc = S_OK;
603 ComPtr<IVirtualBox> pV;
604 {
605 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
606 pV = pThis->mData.m_pVirtualBox;
607 }
608 if (!pV.isNull())
609 {
610 ULONG rev;
611 rc = pV->COMGETTER(Revision)(&rev);
612 if (FAILED_DEAD_INTERFACE(rc))
613 {
614 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
615 {
616 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
617 /* Throw away the VirtualBox reference, it's no longer
618 * usable as VBoxSVC terminated in the mean time. */
619 pThis->mData.m_pVirtualBox.setNull();
620 }
621 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
622 }
623 }
624 else
625 {
626 /* Try to get a new VirtualBox reference straight away, and if
627 * this fails use an increased waiting time as very frequent
628 * restart attempts in some wedged config can cause high CPU
629 * and disk load. */
630 ComPtr<IVirtualBox> pVirtualBox;
631 ComPtr<IToken> pToken;
632 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
633 if (FAILED(rc))
634 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
635 else
636 {
637 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
638 {
639 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
640 /* Update the VirtualBox reference, there's a working
641 * VBoxSVC again from now on. */
642 pThis->mData.m_pVirtualBox = pVirtualBox;
643 pThis->mData.m_pToken = pToken;
644 }
645 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
646 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
647 }
648 }
649 }
650 vrc = RTSemEventWait(sem, cMillies);
651 }
652 return 0;
653}
654
655/* 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