VirtualBox

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

Last change on this file since 70772 was 70585, checked in by vboxsync, 6 years ago

VirtualBoxClientImpl.cpp: Adjusted SDS diagnostic messages. Fixed incorrect hanging indent (on opening parenthesis).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use