/** * Uninitializes the instance and sets the ready flag to FALSE. * Called either from FinalRelease() or by the parent when it gets destroyed. */ void MediumLockToken::uninit() { LogFlowThisFunc(("\n")); /* Enclose the state transition Ready->InUninit->NotReady */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; /* Release the appropriate lock, check is paranoia */ if (!m.pMedium.isNull()) { if (m.fWrite) { HRESULT rc = m.pMedium->unlockWrite(NULL); AssertComRC(rc); } else { HRESULT rc = m.pMedium->unlockRead(NULL); AssertComRC(rc); } m.pMedium.setNull(); } }
/** * Initializes itself by fetching error information from the given error info * object. */ HRESULT VirtualBoxErrorInfo::init(nsIException *aInfo) { AssertReturn(aInfo, E_FAIL); HRESULT rc = S_OK; /* We don't return a failure if talking to nsIException fails below to * protect ourselves from bad nsIException implementations (the * corresponding fields will simply remain null in this case). */ rc = aInfo->GetResult(&m_resultCode); AssertComRC(rc); char *pszMsg; /* No Utf8Str.asOutParam, different allocator! */ rc = aInfo->GetMessage(&pszMsg); AssertComRC(rc); if (NS_SUCCEEDED(rc)) { m_strText = pszMsg; nsMemory::Free(pszMsg); } else m_strText.setNull(); return S_OK; }
/** * Initializes itself by fetching error information from the given error info * object. */ HRESULT VirtualBoxErrorInfo::init(IErrorInfo *aInfo) { AssertReturn(aInfo, E_FAIL); HRESULT rc = S_OK; /* We don't return a failure if talking to IErrorInfo fails below to * protect ourselves from bad IErrorInfo implementations (the * corresponding fields will simply remain null in this case). */ m_resultCode = S_OK; m_resultDetail = 0; rc = aInfo->GetGUID(m_IID.asOutParam()); AssertComRC(rc); Bstr bstrComponent; rc = aInfo->GetSource(bstrComponent.asOutParam()); AssertComRC(rc); m_strComponent = bstrComponent; Bstr bstrText; rc = aInfo->GetDescription(bstrText.asOutParam()); AssertComRC(rc); m_strText = bstrText; return S_OK; }
HRESULT MediumLockListMap::Lock() { if (mIsLocked) return S_OK; HRESULT rc = S_OK; for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin(); it != mMediumLocks.end(); it++) { rc = it->second->Lock(); if (FAILED(rc)) { for (MediumLockListMap::Base::const_iterator it2 = mMediumLocks.begin(); it2 != it; it2++) { HRESULT rc2 = it2->second->Unlock(); AssertComRC(rc2); } break; } } if (SUCCEEDED(rc)) mIsLocked = true; return rc; }
/** * Performs the required actions when a device has been added. * * This means things like running filters and subsequent capturing and * VM attaching. This may result in IPC and temporary lock abandonment. * * @param aDevice The device in question. * @param aUSBDevice The USB device structure. */ void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice) { /* * Validate preconditions. */ AssertReturnVoid(!isWriteLockOnCurrentThread()); AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread()); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", (HostUSBDevice *)aDevice, aDevice->getName().c_str(), aDevice->getStateName(), aDevice->getId().raw())); /* * Run filters on the device. */ if (aDevice->isCapturableOrHeld()) { devLock.release(); HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */); AssertComRC(rc); } NOREF(aUSBDevice); }
/** * Uninitializes the Session object. * * @note Locks this object for writing. */ void Session::uninit() { LogFlowThisFuncEnter(); /* Enclose the state transition Ready->InUninit->NotReady */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) { LogFlowThisFunc(("Already uninitialized.\n")); LogFlowThisFuncLeave(); return; } /* close() needs write lock */ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (mState != SessionState_Unlocked) { Assert(mState == SessionState_Locked || mState == SessionState_Spawning); HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */); AssertComRC(rc); } LogFlowThisFuncLeave(); }
/** * Handle a device which state changed in some significant way. * * This means things like running filters and subsequent capturing and * VM attaching. This may result in IPC and temporary lock abandonment. * * @param aDevice The device. * @param pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters * @param aIgnoreMachine Machine to ignore when running filters. */ void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine) { /* * Validate preconditions. */ AssertReturnVoid(!isWriteLockOnCurrentThread()); AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread()); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n", (HostUSBDevice *)aDevice, aDevice->getName().c_str(), aDevice->getStateName(), aDevice->getId().raw(), (pllOpenedMachines != NULL), // used to be "bool aRunFilters" aIgnoreMachine)); devLock.release(); /* * Run filters if requested to do so. */ if (pllOpenedMachines) { HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine); AssertComRC(rc); } }
HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */) { if (mIsLocked) return S_OK; HRESULT rc = S_OK; for (MediumLockList::Base::iterator it = mMediumLocks.begin(); it != mMediumLocks.end(); it++) { rc = it->Lock(fSkipOverLockedMedia); if (FAILED(rc)) { for (MediumLockList::Base::iterator it2 = mMediumLocks.begin(); it2 != it; it2++) { HRESULT rc2 = it2->Unlock(); AssertComRC(rc2); } break; } } if (SUCCEEDED(rc)) mIsLocked = true; return rc; }
HRESULT ErrorInfoKeeper::restore() { if (mForgot) return S_OK; HRESULT rc = S_OK; #if !defined(VBOX_WITH_XPCOM) ComPtr<IErrorInfo> err; if (!mErrorInfo.isNull()) { rc = mErrorInfo.queryInterfaceTo(err.asOutParam()); AssertComRC(rc); } rc = ::SetErrorInfo(0, err); #else // defined(VBOX_WITH_XPCOM) nsCOMPtr <nsIExceptionService> es; es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); if (NS_SUCCEEDED(rc)) { nsCOMPtr <nsIExceptionManager> em; rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); if (NS_SUCCEEDED(rc)) { ComPtr<nsIException> ex; if (!mErrorInfo.isNull()) { rc = mErrorInfo.queryInterfaceTo(ex.asOutParam()); AssertComRC(rc); } rc = em->SetCurrentException(ex); } } #endif // defined(VBOX_WITH_XPCOM) if (SUCCEEDED(rc)) { mErrorInfo.setNull(); mForgot = true; } return rc; }
/** * Constructs an event queue for the current thread. * * Currently, there can be only one event queue per thread, so if an event * queue for the current thread already exists, this object is simply attached * to the existing event queue. */ EventQueue::EventQueue() { #ifndef VBOX_WITH_XPCOM mThreadId = GetCurrentThreadId(); // force the system to create the message queue for the current thread MSG msg; PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mhThread, 0 /*dwDesiredAccess*/, FALSE /*bInheritHandle*/, DUPLICATE_SAME_ACCESS)) mhThread = INVALID_HANDLE_VALUE; #else // VBOX_WITH_XPCOM mEQCreated = false; mInterrupted = false; // Here we reference the global nsIEventQueueService instance and hold it // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away // from calling StopAcceptingEvents() on all event queues upon destruction of // nsIEventQueueService, and makes sense when, for some reason, this happens // *before* we're able to send a NULL event to stop our event handler thread // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM() // that is performing a global cleanup of everything. A good example of such // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component // is still alive (because it is still referenced): eventually, it results in // a VirtualBox::uninit() call from where it is already not possible to post // NULL to the event thread (because it stopped accepting events). nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService)); if (NS_SUCCEEDED(rc)) { rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQ)); if (rc == NS_ERROR_NOT_AVAILABLE) { rc = mEventQService->CreateThreadEventQueue(); if (NS_SUCCEEDED(rc)) { mEQCreated = true; rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQ)); } } } AssertComRC(rc); #endif // VBOX_WITH_XPCOM }
bool GuestDnDResponse::isProgressCanceled(void) const { BOOL fCanceled; if (!m_progress.isNull()) { HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled); AssertComRC(hr); } else fCanceled = TRUE; return RT_BOOL(fCanceled); }
/** * Marks the operation as complete and attaches full error info. * * See VirtualBoxBase::setError(HRESULT, const GUID &, const wchar_t * *, const char *, ...) for more info. * * @param aResultCode Operation result (error) code, must not be S_OK. * @param aIID IID of the interface that defines the error. * @param aComponent Name of the component that generates the error. * @param aText Error message (must not be null), an RTStrPrintf-like * format string in UTF-8 encoding. * @param va List of arguments for the format string. */ HRESULT Progress::i_notifyCompleteV(HRESULT aResultCode, const GUID &aIID, const char *pcszComponent, const char *aText, va_list va) { Utf8Str text(aText, va); AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mCompleted == FALSE, E_FAIL); if (mCanceled && SUCCEEDED(aResultCode)) aResultCode = E_FAIL; mCompleted = TRUE; mResultCode = aResultCode; AssertReturn(FAILED(aResultCode), E_FAIL); ComObjPtr<VirtualBoxErrorInfo> errorInfo; HRESULT rc = errorInfo.createObject(); AssertComRC(rc); if (SUCCEEDED(rc)) { errorInfo->init(aResultCode, aIID, pcszComponent, text); errorInfo.queryInterfaceTo(mErrorInfo.asOutParam()); } #if !defined VBOX_COM_INPROC /* remove from the global collection of pending progress operations */ if (mParent) mParent->i_removeProgress(mId.ref()); #endif /* wake up all waiting threads */ if (mWaitersCount > 0) RTSemEventMultiSignal(mCompletedSem); return rc; }
/** * Unlocks a machine associated with the current session. * * @param aFinalRelease called as a result of FinalRelease() * @param aFromServer called as a result of Uninitialize() * * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize(). * @note Locks this object for writing. */ HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) { LogFlowThisFuncEnter(); LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n", aFinalRelease, aFromServer)); AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType)); if (mState != SessionState_Locked) { Assert(mState == SessionState_Spawning); /* The session object is going to be uninitialized before it has been * assigned a direct console of the machine the client requested to open * a remote session to using IVirtualBox:: openRemoteSession(). It is OK * only if this close request comes from the server (for example, it * detected that the VM process it started terminated before opening a * direct session). Otherwise, it means that the client is too fast and * trying to close the session before waiting for the progress object it * got from IVirtualBox:: openRemoteSession() to complete, so assert. */ Assert(aFromServer); mState = SessionState_Unlocked; mType = SessionType_Null; Assert(!mClientTokenHolder); LogFlowThisFuncLeave(); return S_OK; } /* go to the closing state */ mState = SessionState_Unlocking; if (mType == SessionType_WriteLock) { if (!mConsole.isNull()) { mConsole->uninit(); mConsole.setNull(); } } else { mRemoteMachine.setNull(); mRemoteConsole.setNull(); } ComPtr<IProgress> progress; if (!aFinalRelease && !aFromServer) { /* * We trigger OnSessionEnd() only when the session closes itself using * Close(). Note that if isFinalRelease = TRUE here, this means that * the client process has already initialized the termination procedure * without issuing Close() and the IPC channel is no more operational -- * so we cannot call the server's method (it will definitely fail). The * server will instead simply detect the abnormal client death (since * OnSessionEnd() is not called) and reset the machine state to Aborted. */ /* * while waiting for OnSessionEnd() to complete one of our methods * can be called by the server (for example, Uninitialize(), if the * direct session has initiated a closure just a bit before us) so * we need to release the lock to avoid deadlocks. The state is already * SessionState_Closing here, so it's safe. */ alock.release(); LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n")); HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam()); LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc)); alock.acquire(); /* * If we get E_UNEXPECTED this means that the direct session has already * been closed, we're just too late with our notification and nothing more * * bird: Seems E_ACCESSDENIED is what gets returned these days; see * VirtualBoxBase::addCaller. */ if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED)) rc = S_OK; #ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */ AssertComRC(rc); #endif } mControl.setNull(); if (mType == SessionType_WriteLock) { if (mClientTokenHolder) { delete mClientTokenHolder; mClientTokenHolder = NULL; } if (!aFinalRelease && !aFromServer) { /* * Wait for the server to grab the semaphore and destroy the session * machine (allowing us to open a new session with the same machine * once this method returns) */ Assert(!!progress); if (progress) progress->WaitForCompletion(-1); } } mState = SessionState_Unlocked; mType = SessionType_Null; /* release the VirtualBox instance as the very last step */ mVirtualBox.setNull(); LogFlowThisFuncLeave(); return S_OK; }
/** * Process any relevant changes in the attached USB devices. * * Except for the first call, this is always running on the service thread. */ void USBProxyService::processChanges(void) { LogFlowThisFunc(("\n")); /* * Get the sorted list of USB devices. */ PUSBDEVICE pDevices = getDevices(); pDevices = sortDevices(pDevices); // get a list of all running machines while we're outside the lock // (getOpenedMachines requests higher priority locks) SessionMachinesList llOpenedMachines; mHost->parent()->getOpenedMachines(llOpenedMachines); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* * Compare previous list with the new list of devices * and merge in any changes while notifying Host. */ HostUSBDeviceList::iterator it = this->mDevices.begin(); while ( it != mDevices.end() || pDevices) { ComObjPtr<HostUSBDevice> pHostDevice; if (it != mDevices.end()) pHostDevice = *it; /* * Assert that the object is still alive (we still reference it in * the collection and we're the only one who calls uninit() on it. */ AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice); AssertComRC(devCaller.rc()); /* * Lock the device object since we will read/write its * properties. All Host callbacks also imply the object is locked. */ AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice COMMA_LOCKVAL_SRC_POS); /* * Compare. */ int iDiff; if (pHostDevice.isNull()) iDiff = 1; else { if (!pDevices) iDiff = -1; else iDiff = pHostDevice->compare(pDevices); } if (!iDiff) { /* * The device still there, update the state and move on. The PUSBDEVICE * structure is eaten by updateDeviceState / HostUSBDevice::updateState(). */ PUSBDEVICE pCur = pDevices; pDevices = pDevices->pNext; pCur->pPrev = pCur->pNext = NULL; bool fRunFilters = false; SessionMachine *pIgnoreMachine = NULL; devLock.release(); alock.release(); if (updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine)) deviceChanged(pHostDevice, (fRunFilters ? &llOpenedMachines : NULL), pIgnoreMachine); alock.acquire(); it++; } else { if (iDiff > 0) { /* * Head of pDevices was attached. */ PUSBDEVICE pNew = pDevices; pDevices = pDevices->pNext; pNew->pPrev = pNew->pNext = NULL; ComObjPtr<HostUSBDevice> NewObj; NewObj.createObject(); NewObj->init(pNew, this); Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n", (HostUSBDevice *)NewObj, NewObj->getName().c_str(), NewObj->getStateName(), pNew, pNew->idVendor, pNew->idProduct, pNew->pszProduct, pNew->pszManufacturer)); mDevices.insert(it, NewObj); devLock.release(); alock.release(); deviceAdded(NewObj, llOpenedMachines, pNew); alock.acquire(); } else { /* * Check if the device was actually detached or logically detached * as the result of a re-enumeration. */ if (!pHostDevice->wasActuallyDetached()) it++; else { it = mDevices.erase(it); devLock.release(); alock.release(); deviceRemoved(pHostDevice); Log(("USBProxyService::processChanges: detached %p {%s}\n", (HostUSBDevice *)pHostDevice, pHostDevice->getName().c_str())); /* from now on, the object is no more valid, * uninitialize to avoid abuse */ devCaller.release(); pHostDevice->uninit(); alock.acquire(); } } } } /* while */ LogFlowThisFunc(("returns void\n")); }
/** * Called to copy over the progress information from @a pOtherProgress. * * @param pOtherProgress The source of the information. * @param fEarly Early copy. * * @note The caller owns the write lock and as cleared mptrOtherProgress * already (or we might recurse forever)! */ void ProgressProxy::copyProgressInfo(IProgress *pOtherProgress, bool fEarly) { HRESULT hrc; LogFlowThisFunc(("\n")); NOREF(fEarly); /* * No point in doing this if the progress object was canceled already. */ if (!mCanceled) { /* Detect if the other progress object was canceled. */ BOOL fCanceled; hrc = pOtherProgress->COMGETTER(Canceled)(&fCanceled); if (FAILED(hrc)) fCanceled = FALSE; if (fCanceled) { LogFlowThisFunc(("Canceled\n")); mCanceled = TRUE; if (m_pfnCancelCallback) m_pfnCancelCallback(m_pvCancelUserArg); } else { /* Has it completed? */ BOOL fCompleted; hrc = pOtherProgress->COMGETTER(Completed)(&fCompleted); if (FAILED(hrc)) fCompleted = TRUE; Assert(fCompleted || fEarly); if (fCompleted) { /* Check the result. */ LONG hrcResult; hrc = pOtherProgress->COMGETTER(ResultCode)(&hrcResult); if (FAILED(hrc)) hrcResult = hrc; if (SUCCEEDED((HRESULT)hrcResult)) LogFlowThisFunc(("Succeeded\n")); else { /* Get the error information. */ ComPtr<IVirtualBoxErrorInfo> ptrErrorInfo; hrc = pOtherProgress->COMGETTER(ErrorInfo)(ptrErrorInfo.asOutParam()); if (SUCCEEDED(hrc) && !ptrErrorInfo.isNull()) { Bstr bstrIID; hrc = ptrErrorInfo->COMGETTER(InterfaceID)(bstrIID.asOutParam()); AssertComRC(hrc); if (FAILED(hrc)) bstrIID.setNull(); Bstr bstrComponent; hrc = ptrErrorInfo->COMGETTER(Component)(bstrComponent.asOutParam()); AssertComRC(hrc); if (FAILED(hrc)) bstrComponent = "failed"; Bstr bstrText; hrc = ptrErrorInfo->COMGETTER(Text)(bstrText.asOutParam()); AssertComRC(hrc); if (FAILED(hrc)) bstrText = "<failed>"; Utf8Str strText(bstrText); LogFlowThisFunc(("Got ErrorInfo(%s); hrcResult=%Rhrc\n", strText.c_str(), hrcResult)); Progress::notifyComplete((HRESULT)hrcResult, Guid(bstrIID).ref(), Utf8Str(bstrComponent).c_str(), "%s", strText.c_str()); } else { LogFlowThisFunc(("ErrorInfo failed with hrc=%Rhrc; hrcResult=%Rhrc\n", hrc, hrcResult)); Progress::notifyComplete((HRESULT)hrcResult, COM_IIDOF(IProgress), "ProgressProxy", tr("No error info")); } } } else LogFlowThisFunc(("Not completed\n")); } } else LogFlowThisFunc(("Already canceled\n")); /* * Did cancelable state change (point of no return)? */ if (mCancelable && !mCompleted && !mCanceled) { BOOL fCancelable; hrc = pOtherProgress->COMGETTER(Cancelable)(&fCancelable); AssertComRC(hrc); if (SUCCEEDED(hrc) && !fCancelable) { LogFlowThisFunc(("point-of-no-return reached\n")); mCancelable = FALSE; } } }
int GuestDnDResponse::setProgress(unsigned uPercentage, uint32_t uStatus, int rcOp /* = VINF_SUCCESS */, const Utf8Str &strMsg /* = "" */) { LogFlowFunc(("uStatus=%RU32, uPercentage=%RU32, rcOp=%Rrc, strMsg=%s\n", uStatus, uPercentage, rcOp, strMsg.c_str())); int rc = VINF_SUCCESS; if (!m_progress.isNull()) { BOOL fCompleted; HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted); AssertComRC(hr); BOOL fCanceled; hr = m_progress->COMGETTER(Canceled)(&fCanceled); AssertComRC(hr); LogFlowFunc(("Current: fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled)); if (!fCompleted) { switch (uStatus) { case DragAndDropSvc::DND_PROGRESS_ERROR: { hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), m_parent->getComponentName(), strMsg.c_str()); reset(); break; } case DragAndDropSvc::DND_PROGRESS_CANCELLED: { hr = m_progress->i_notifyComplete(S_OK); AssertComRC(hr); reset(); break; } case DragAndDropSvc::DND_PROGRESS_RUNNING: case DragAndDropSvc::DND_PROGRESS_COMPLETE: { if (!fCanceled) { hr = m_progress->SetCurrentOperationProgress(uPercentage); AssertComRC(hr); if ( uStatus == DragAndDropSvc::DND_PROGRESS_COMPLETE || uPercentage >= 100) { hr = m_progress->i_notifyComplete(S_OK); AssertComRC(hr); } } break; } default: break; } } hr = m_progress->COMGETTER(Completed)(&fCompleted); AssertComRC(hr); hr = m_progress->COMGETTER(Canceled)(&fCanceled); AssertComRC(hr); LogFlowFunc(("New: fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled)); } LogFlowFuncLeaveRC(rc); return rc; }
void ErrorInfo::init(bool aKeepObj /* = false */) { HRESULT rc = E_FAIL; #if !defined(VBOX_WITH_XPCOM) ComPtr<IErrorInfo> err; rc = ::GetErrorInfo(0, err.asOutParam()); if (rc == S_OK && err) { if (aKeepObj) mErrorInfo = err; ComPtr<IVirtualBoxErrorInfo> info; rc = err.queryInterfaceTo(info.asOutParam()); if (SUCCEEDED(rc) && info) init(info); if (!mIsFullAvailable) { bool gotSomething = false; rc = err->GetGUID(mInterfaceID.asOutParam()); gotSomething |= SUCCEEDED(rc); if (SUCCEEDED(rc)) GetInterfaceNameByIID(mInterfaceID.ref(), mInterfaceName.asOutParam()); rc = err->GetSource(mComponent.asOutParam()); gotSomething |= SUCCEEDED(rc); rc = err->GetDescription(mText.asOutParam()); gotSomething |= SUCCEEDED(rc); if (gotSomething) mIsBasicAvailable = true; AssertMsg(gotSomething, ("Nothing to fetch!\n")); } } #else // defined(VBOX_WITH_XPCOM) nsCOMPtr<nsIExceptionService> es; es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); if (NS_SUCCEEDED(rc)) { nsCOMPtr<nsIExceptionManager> em; rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); if (NS_SUCCEEDED(rc)) { ComPtr<nsIException> ex; rc = em->GetCurrentException(ex.asOutParam()); if (NS_SUCCEEDED(rc) && ex) { if (aKeepObj) mErrorInfo = ex; ComPtr<IVirtualBoxErrorInfo> info; rc = ex.queryInterfaceTo(info.asOutParam()); if (NS_SUCCEEDED(rc) && info) init(info); if (!mIsFullAvailable) { bool gotSomething = false; rc = ex->GetResult(&mResultCode); gotSomething |= NS_SUCCEEDED(rc); char *pszMsg; rc = ex->GetMessage(&pszMsg); gotSomething |= NS_SUCCEEDED(rc); if (NS_SUCCEEDED(rc)) { mText = Bstr(pszMsg); nsMemory::Free(pszMsg); } if (gotSomething) mIsBasicAvailable = true; AssertMsg(gotSomething, ("Nothing to fetch!\n")); } // set the exception to NULL (to emulate Win32 behavior) em->SetCurrentException(NULL); rc = NS_OK; } } } /* Ignore failure when called after nsComponentManagerImpl::Shutdown(). */ else if (rc == NS_ERROR_UNEXPECTED) rc = NS_OK; AssertComRC(rc); #endif // defined(VBOX_WITH_XPCOM) }
int NetworkManager::processParameterReqList(const Client& client, const uint8_t *pu8ReqList, int cReqList, std::vector<RawOption>& extra) { int rc; const Lease l = client.lease(); const NetworkConfigEntity *pNetCfg = l.getConfig(); /* * XXX: Brute-force. Unfortunately, there's no notification event * for changes. Should at least cache the options for a short * time, enough to last discover/offer/request/ack cycle. */ typedef std::map< int, std::pair<std::string, int> > DhcpOptionMap; DhcpOptionMap OptMap; if (!m->m_DhcpServer.isNull()) { com::SafeArray<BSTR> strings; com::Bstr str; HRESULT hrc; int OptCode, OptEncoding; char *pszOptText; strings.setNull(); hrc = m->m_DhcpServer->COMGETTER(GlobalOptions)(ComSafeArrayAsOutParam(strings)); AssertComRC(hrc); for (size_t i = 0; i < strings.size(); ++i) { com::Utf8Str encoded(strings[i]); rc = parseDhcpOptionText(encoded.c_str(), &OptCode, &pszOptText, &OptEncoding); if (!RT_SUCCESS(rc)) continue; OptMap[OptCode] = std::make_pair(pszOptText, OptEncoding); } const RTMAC &mac = client.getMacAddress(); char strMac[6*2+1] = ""; RTStrPrintf(strMac, sizeof(strMac), "%02x%02x%02x%02x%02x%02x", mac.au8[0], mac.au8[1], mac.au8[2], mac.au8[3], mac.au8[4], mac.au8[5]); strings.setNull(); hrc = m->m_DhcpServer->GetMacOptions(com::Bstr(strMac).raw(), ComSafeArrayAsOutParam(strings)); AssertComRC(hrc); for (size_t i = 0; i < strings.size(); ++i) { com::Utf8Str text(strings[i]); rc = parseDhcpOptionText(text.c_str(), &OptCode, &pszOptText, &OptEncoding); if (!RT_SUCCESS(rc)) continue; OptMap[OptCode] = std::make_pair(pszOptText, OptEncoding); } } /* request parameter list */ RawOption opt; bool fIgnore; uint8_t u8Req; for (int idxParam = 0; idxParam < cReqList; ++idxParam) { fIgnore = false; RT_ZERO(opt); u8Req = opt.u8OptId = pu8ReqList[idxParam]; switch(u8Req) { case RTNET_DHCP_OPT_SUBNET_MASK: ((PRTNETADDRIPV4)opt.au8RawOpt)->u = pNetCfg->netmask().u; opt.cbRawOpt = sizeof(RTNETADDRIPV4); break; case RTNET_DHCP_OPT_ROUTERS: case RTNET_DHCP_OPT_DNS: { const Ipv4AddressContainer lst = g_ConfigurationManager->getAddressList(u8Req); PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0]; for (Ipv4AddressConstIterator it = lst.begin(); it != lst.end(); ++it) { *pAddresses = (*it); pAddresses++; opt.cbRawOpt += sizeof(RTNETADDRIPV4); } if (lst.empty()) fIgnore = true; } break; case RTNET_DHCP_OPT_DOMAIN_NAME: { std::string domainName = g_ConfigurationManager->getString(u8Req); if (domainName == g_ConfigurationManager->m_noString) { fIgnore = true; break; } char *pszDomainName = (char *)&opt.au8RawOpt[0]; strcpy(pszDomainName, domainName.c_str()); opt.cbRawOpt = domainName.length(); } break; default: { DhcpOptionMap::const_iterator it = OptMap.find((int)u8Req); if (it == OptMap.end()) { Log(("opt: %d is ignored\n", u8Req)); fIgnore = true; } else { std::string OptText((*it).second.first); int OptEncoding((*it).second.second); rc = fillDhcpOption(opt, OptText, OptEncoding); if (!RT_SUCCESS(rc)) { fIgnore = true; break; } } } break; } if (!fIgnore) extra.push_back(opt); } return VINF_SUCCESS; }
HRESULT Shutdown() { HRESULT rc = S_OK; #if !defined(VBOX_WITH_XPCOM) /* EventQueue::uninit reference counting fun. */ RTTHREAD hSelf = RTThreadSelf(); if ( hSelf == gCOMMainThread && hSelf != NIL_RTTHREAD) { if (-- gCOMMainInitCount == 0) { EventQueue::uninit(); ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD); } } CoUninitialize(); #else /* !defined (VBOX_WITH_XPCOM) */ nsCOMPtr<nsIEventQueue> eventQ; rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); if (NS_SUCCEEDED(rc) || rc == NS_ERROR_NOT_AVAILABLE) { /* NS_ERROR_NOT_AVAILABLE seems to mean that * nsIEventQueue::StopAcceptingEvents() has been called (see * nsEventQueueService.cpp). We hope that this error code always means * just that in this case and assume that we're on the main thread * (it's a kind of unexpected behavior if a non-main thread ever calls * StopAcceptingEvents() on the main event queue). */ PRBool isOnMainThread = PR_FALSE; if (NS_SUCCEEDED(rc)) { rc = eventQ->IsOnCurrentThread(&isOnMainThread); eventQ = nsnull; /* early release before shutdown */ } else { isOnMainThread = PR_TRUE; rc = NS_OK; } if (NS_SUCCEEDED(rc) && isOnMainThread) { /* only the main thread needs to uninitialize XPCOM and only if * init counter drops to zero */ if (--gXPCOMInitCount == 0) { EventQueue::uninit(); rc = NS_ShutdownXPCOM(nsnull); /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to * true. Reset it back to false. */ bool wasInited = ASMAtomicXchgBool(&gIsXPCOMInitialized, false); Assert(wasInited == true); NOREF(wasInited); # if defined (XPCOM_GLUE) XPCOMGlueShutdown(); # endif } } } #endif /* !defined(VBOX_WITH_XPCOM) */ AssertComRC(rc); return rc; }
/** * Initializes the COM runtime. * * This method must be called on each thread of the client application that * wants to access COM facilities. The initialization must be performed before * calling any other COM method or attempting to instantiate COM objects. * * On platforms using XPCOM, this method uses the following scheme to search for * XPCOM runtime: * * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies * is used to search XPCOM libraries and components. If this method fails to * initialize XPCOM runtime using this path, it will immediately return a * failure and will NOT check for other paths as described below. * * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the * given order: * * a) Compiled-in application data directory (as returned by * RTPathAppPrivateArch()) * b) "/usr/lib/virtualbox" (Linux only) * c) "/opt/VirtualBox" (Linux only) * * The first path for which the initialization succeeds will be used. * * On MS COM platforms, the COM runtime is provided by the system and does not * need to be searched for. * * Once the COM subsystem is no longer necessary on a given thread, Shutdown() * must be called to free resources allocated for it. Note that a thread may * call Initialize() several times but for each of tese calls there must be a * corresponding Shutdown() call. * * @return S_OK on success and a COM result code in case of failure. */ HRESULT Initialize(bool fGui) { HRESULT rc = E_FAIL; #if !defined(VBOX_WITH_XPCOM) /* * We initialize COM in GUI thread in STA, to be compliant with QT and * OLE requirments (for example to allow D&D), while other threads * initialized in regular MTA. To allow fast proxyless access from * GUI thread to COM objects, we explicitly provide our COM objects * with free threaded marshaller. * !!!!! Please think twice before touching this code !!!!! */ DWORD flags = fGui ? COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY : COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY; rc = CoInitializeEx(NULL, flags); /* the overall result must be either S_OK or S_FALSE (S_FALSE means * "already initialized using the same apartment model") */ AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc)); /* To be flow compatible with the XPCOM case, we return here if this isn't * the main thread or if it isn't its first initialization call. * Note! CoInitializeEx and CoUninitialize does it's own reference * counting, so this exercise is entirely for the EventQueue init. */ bool fRc; RTTHREAD hSelf = RTThreadSelf(); if (hSelf != NIL_RTTHREAD) ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc); else fRc = false; if (fGui) Assert(RTThreadIsMain(hSelf)); if (!fRc) { if ( gCOMMainThread == hSelf && SUCCEEDED(rc)) gCOMMainInitCount++; AssertComRC(rc); return rc; } Assert(RTThreadIsMain(hSelf)); /* this is the first main thread initialization */ Assert(gCOMMainInitCount == 0); if (SUCCEEDED(rc)) gCOMMainInitCount = 1; #else /* !defined (VBOX_WITH_XPCOM) */ /* Unused here */ NOREF(fGui); if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true) { /* XPCOM is already initialized on the main thread, no special * initialization is necessary on additional threads. Just increase * the init counter if it's a main thread again (to correctly support * nested calls to Initialize()/Shutdown() for compatibility with * Win32). */ nsCOMPtr<nsIEventQueue> eventQ; rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); if (NS_SUCCEEDED(rc)) { PRBool isOnMainThread = PR_FALSE; rc = eventQ->IsOnCurrentThread(&isOnMainThread); if (NS_SUCCEEDED(rc) && isOnMainThread) ++gXPCOMInitCount; } AssertComRC(rc); return rc; } Assert(RTThreadIsMain(RTThreadSelf())); /* this is the first initialization */ gXPCOMInitCount = 1; bool const fInitEventQueues = true; /* prepare paths for registry files */ char szCompReg[RTPATH_MAX]; char szXptiDat[RTPATH_MAX]; int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg)); AssertRCReturn(vrc, NS_ERROR_FAILURE); strcpy(szXptiDat, szCompReg); vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); LogFlowFunc(("component registry : \"%s\"\n", szCompReg)); LogFlowFunc(("XPTI data file : \"%s\"\n", szXptiDat)); #if defined (XPCOM_GLUE) XPCOMGlueStartup(nsnull); #endif static const char *kAppPathsToProbe[] = { NULL, /* 0: will use VBOX_APP_HOME */ NULL, /* 1: will try RTPathAppPrivateArch() */ #ifdef RT_OS_LINUX "/usr/lib/virtualbox", "/opt/VirtualBox", #elif RT_OS_SOLARIS "/opt/VirtualBox/amd64", "/opt/VirtualBox/i386", #elif RT_OS_DARWIN "/Application/VirtualBox.app/Contents/MacOS", #endif }; /* Find out the directory where VirtualBox binaries are located */ for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i) { char szAppHomeDir[RTPATH_MAX]; if (i == 0) { /* Use VBOX_APP_HOME if present */ vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL); if (vrc == VERR_ENV_VAR_NOT_FOUND) continue; AssertRC(vrc); } else if (i == 1) { /* Use RTPathAppPrivateArch() first */ vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir)); AssertRC(vrc); } else { /* Iterate over all other paths */ szAppHomeDir[RTPATH_MAX - 1] = '\0'; strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1); vrc = VINF_SUCCESS; } if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } char szCompDir[RTPATH_MAX]; vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components"); if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } LogFlowFunc(("component directory : \"%s\"\n", szCompDir)); nsCOMPtr<DirectoryServiceProvider> dsProv; dsProv = new DirectoryServiceProvider(); if (dsProv) rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir); else rc = NS_ERROR_OUT_OF_MEMORY; if (NS_FAILED(rc)) break; /* Setup the application path for NS_InitXPCOM2. Note that we properly * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory * service provider but it seems to be activated after the directory * service is used for the first time (see the source NS_InitXPCOM2). So * use the same value here to be on the safe side. */ nsCOMPtr <nsIFile> appDir; { char *appDirCP = NULL; vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir); if (RT_SUCCESS(vrc)) { nsCOMPtr<nsILocalFile> file; rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP), PR_FALSE, getter_AddRefs(file)); if (NS_SUCCEEDED(rc)) appDir = do_QueryInterface(file, &rc); RTStrFree(appDirCP); } else rc = NS_ERROR_FAILURE; } if (NS_FAILED(rc)) break; /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that * still use it instead of the directory service happy */ vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir); AssertRC(vrc); /* Finally, initialize XPCOM */ { nsCOMPtr<nsIServiceManager> serviceManager; rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv); if (NS_SUCCEEDED(rc)) { nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager, &rc); if (NS_SUCCEEDED(rc)) { rc = registrar->AutoRegister(nsnull); if (NS_SUCCEEDED(rc)) { /* We succeeded, stop probing paths */ LogFlowFunc(("Succeeded.\n")); break; } } } } /* clean up before the new try */ rc = NS_ShutdownXPCOM(nsnull); if (i == 0) { /* We failed with VBOX_APP_HOME, don't probe other paths */ break; } } #endif /* !defined (VBOX_WITH_XPCOM) */ // for both COM and XPCOM, we only get here if this is the main thread; // only then initialize the autolock system (AutoLock.cpp) Assert(RTThreadIsMain(RTThreadSelf())); util::InitAutoLockSystem(); AssertComRC(rc); /* * Init the main event queue (ASSUMES it cannot fail). */ if (SUCCEEDED(rc)) EventQueue::init(); return rc; }