VirtualBox

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

Last change on this file since 73768 was 73003, checked in by vboxsync, 6 years ago

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

  • 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 73003 2018-07-09 11:09:32Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.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 VirtualBox 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 setErrorBoth(VBOX_E_IPRT_ERROR, vrc, 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 setErrorBoth(VBOX_E_IPRT_ERROR, vrc, 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