HRESULT USBDeviceFilters::insertDeviceFilter(ULONG aPosition, const ComPtr<IUSBDeviceFilter> &aFilter) { #ifdef VBOX_WITH_USB /* the machine needs to be mutable */ AutoMutableStateDependency adep(m->pParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); IUSBDeviceFilter *iFilter = aFilter; ComObjPtr<USBDeviceFilter> pFilter = static_cast<USBDeviceFilter*>(iFilter); if (pFilter->mInList) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("The given USB device pFilter is already in the list")); /* backup the list before modification */ m->llDeviceFilters.backup(); /* iterate to the position... */ DeviceFilterList::iterator it; if (aPosition < m->llDeviceFilters->size()) { it = m->llDeviceFilters->begin(); std::advance(it, aPosition); } else it = m->llDeviceFilters->end(); /* ...and insert */ m->llDeviceFilters->insert(it, pFilter); pFilter->mInList = true; /* notify the proxy (only when it makes sense) */ if (pFilter->i_getData().mActive && Global::IsOnline(adep.machineState()) && pFilter->i_getData().mRemote.isMatch(false)) { USBProxyService *pProxySvc = m->pHost->i_usbProxyService(); ComAssertRet(pProxySvc, E_FAIL); ComAssertRet(pFilter->i_getId() == NULL, E_FAIL); pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter); } alock.release(); AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); m->pParent->i_setModified(Machine::IsModified_USB); mlock.release(); return S_OK; #else /* VBOX_WITH_USB */ NOREF(aPosition); NOREF(aFilter); ReturnComNotImplemented(); #endif /* VBOX_WITH_USB */ }
/** * Called by setter methods of all USB device filters. * * @note Locks nothing. */ HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter, BOOL aActiveChanged /* = FALSE */) { AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); /* we need the machine state */ AutoAnyStateDependency adep(m->pParent); AssertComRCReturnRC(adep.rc()); /* nothing to do if the machine isn't running */ if (!Global::IsOnline (adep.machineState())) return S_OK; /* we don't modify our data fields -- no need to lock */ if ( aFilter->mInList && m->pParent->isRegistered()) { USBProxyService *service = m->pHost->usbProxyService(); ComAssertRet(service, E_FAIL); if (aActiveChanged) { if (aFilter->getData().mRemote.isMatch (false)) { /* insert/remove the filter from the proxy */ if (aFilter->getData().mActive) { ComAssertRet(aFilter->getId() == NULL, E_FAIL); aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); } else { ComAssertRet(aFilter->getId() != NULL, E_FAIL); service->removeFilter(aFilter->getId()); aFilter->getId() = NULL; } } } else { if (aFilter->getData().mActive) { /* update the filter in the proxy */ ComAssertRet(aFilter->getId() != NULL, E_FAIL); service->removeFilter(aFilter->getId()); if (aFilter->getData().mRemote.isMatch (false)) { aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); } } } } return S_OK; }
/** * Notifies the proxy service about all filters as requested by the * @a aInsertFilters argument. * * @param aInsertFilters @c true to insert filters, @c false to remove. * * @note Locks this object for reading. */ HRESULT USBController::notifyProxy (bool aInsertFilters) { LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters)); AutoCaller autoCaller(this); AssertComRCReturn (autoCaller.rc(), false); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); USBProxyService *service = m->pHost->usbProxyService(); AssertReturn(service, E_FAIL); DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); while (it != m->llDeviceFilters->end()) { USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */ /* notify the proxy (only if the filter is active) */ if (flt->getData().mActive && flt->getData().mRemote.isMatch (false) /* and if the filter is NOT remote */ ) { if (aInsertFilters) { AssertReturn(flt->getId() == NULL, E_FAIL); flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); } else { /* It's possible that the given filter was not inserted the proxy * when this method gets called (as a result of an early VM * process crash for example. So, don't assert that ID != NULL. */ if (flt->getId() != NULL) { service->removeFilter(flt->getId()); flt->getId() = NULL; } } } ++ it; } return S_OK; }
/** * The service thread created by start(). * * @param Thread The thread handle. * @param pvUser Pointer to the USBProxyService instance. */ /*static*/ DECLCALLBACK(int) USBProxyService::serviceThread(RTTHREAD /* Thread */, void *pvUser) { USBProxyService *pThis = (USBProxyService *)pvUser; LogFlowFunc(("pThis=%p\n", pThis)); pThis->serviceThreadInit(); int rc = VINF_SUCCESS; /* * Processing loop. */ for (;;) { rc = pThis->wait(RT_INDEFINITE_WAIT); if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT) break; if (pThis->mTerminate) break; pThis->processChanges(); } pThis->serviceThreadTerm(); LogFlowFunc(("returns %Rrc\n", rc)); return rc; }
/** @note Locks objects for writing! */ void USBController::rollback() { AutoCaller autoCaller(this); AssertComRCReturnVoid(autoCaller.rc()); /* we need the machine state */ AutoAnyStateDependency adep(m->pParent); AssertComRCReturnVoid(adep.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); m->bd.rollback(); #ifdef VBOX_WITH_USB if (m->llDeviceFilters.isBackedUp()) { USBProxyService *service = m->pHost->usbProxyService(); Assert(service); /* uninitialize all new filters (absent in the backed up list) */ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); DeviceFilterList *backedList = m->llDeviceFilters.backedUpData(); while (it != m->llDeviceFilters->end()) { if (std::find (backedList->begin(), backedList->end(), *it) == backedList->end()) { /* notify the proxy (only when it makes sense) */ if ((*it)->getData().mActive && Global::IsOnline (adep.machineState()) && (*it)->getData().mRemote.isMatch (false)) { USBDeviceFilter *filter = *it; Assert(filter->getId() != NULL); service->removeFilter(filter->getId()); filter->getId() = NULL; } (*it)->uninit(); } ++ it; } if (Global::IsOnline (adep.machineState())) { /* find all removed old filters (absent in the new list) * and insert them back to the USB proxy */ it = backedList->begin(); while (it != backedList->end()) { if (std::find (m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) == m->llDeviceFilters->end()) { /* notify the proxy (only when necessary) */ if ((*it)->getData().mActive && (*it)->getData().mRemote.isMatch (false)) { USBDeviceFilter *flt = *it; /* resolve ambiguity */ Assert(flt->getId() == NULL); flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); } } ++ it; } } /* restore the list */ m->llDeviceFilters.rollback(); } /* here we don't depend on the machine state any more */ adep.release(); /* rollback any changes to filters after restoring the list */ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); while (it != m->llDeviceFilters->end()) { if ((*it)->isModified()) { (*it)->rollback(); /* call this to notify the USB proxy about changes */ onDeviceFilterChange(*it); } ++it; } #endif /* VBOX_WITH_USB */ }
STDMETHODIMP USBController::RemoveDeviceFilter(ULONG aPosition, IUSBDeviceFilter **aFilter) { #ifdef VBOX_WITH_USB CheckComArgOutPointerValid(aFilter); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* the machine needs to be mutable */ AutoMutableStateDependency adep(m->pParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (!m->llDeviceFilters->size()) return setError(E_INVALIDARG, tr("The USB device filter list is empty")); if (aPosition >= m->llDeviceFilters->size()) return setError(E_INVALIDARG, tr("Invalid position: %lu (must be in range [0, %lu])"), aPosition, m->llDeviceFilters->size() - 1); /* backup the list before modification */ m->llDeviceFilters.backup(); ComObjPtr<USBDeviceFilter> filter; { /* iterate to the position... */ DeviceFilterList::iterator it = m->llDeviceFilters->begin(); std::advance (it, aPosition); /* ...get an element from there... */ filter = *it; /* ...and remove */ filter->mInList = false; m->llDeviceFilters->erase (it); } /* cancel sharing (make an independent copy of data) */ filter->unshare(); filter.queryInterfaceTo(aFilter); /* notify the proxy (only when it makes sense) */ if (filter->getData().mActive && Global::IsOnline(adep.machineState()) && filter->getData().mRemote.isMatch (false)) { USBProxyService *service = m->pHost->usbProxyService(); ComAssertRet(service, E_FAIL); ComAssertRet(filter->getId() != NULL, E_FAIL); service->removeFilter(filter->getId()); filter->getId() = NULL; } alock.release(); AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); m->pParent->setModified(Machine::IsModified_USB); mlock.release(); return S_OK; #else /* VBOX_WITH_USB */ NOREF(aPosition); NOREF(aFilter); ReturnComNotImplemented(); #endif /* VBOX_WITH_USB */ }
STDMETHODIMP USBController::InsertDeviceFilter(ULONG aPosition, IUSBDeviceFilter *aFilter) { #ifdef VBOX_WITH_USB CheckComArgNotNull(aFilter); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* the machine needs to be mutable */ AutoMutableStateDependency adep(m->pParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); ComObjPtr<USBDeviceFilter> filter = static_cast<USBDeviceFilter*>(aFilter); // @todo r=dj make sure the input object is actually from us // if (!filter) // return setError (E_INVALIDARG, // tr ("The given USB device filter is not created within " // "this VirtualBox instance")); if (filter->mInList) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("The given USB device filter is already in the list")); /* backup the list before modification */ m->llDeviceFilters.backup(); /* iterate to the position... */ DeviceFilterList::iterator it; if (aPosition < m->llDeviceFilters->size()) { it = m->llDeviceFilters->begin(); std::advance (it, aPosition); } else it = m->llDeviceFilters->end(); /* ...and insert */ m->llDeviceFilters->insert (it, filter); filter->mInList = true; /* notify the proxy (only when it makes sense) */ if (filter->getData().mActive && Global::IsOnline(adep.machineState()) && filter->getData().mRemote.isMatch (false)) { USBProxyService *service = m->pHost->usbProxyService(); ComAssertRet(service, E_FAIL); ComAssertRet(filter->getId() == NULL, E_FAIL); filter->getId() = service->insertFilter (&filter->getData().mUSBFilter); } alock.release(); AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); m->pParent->setModified(Machine::IsModified_USB); mlock.release(); return S_OK; #else /* VBOX_WITH_USB */ NOREF(aPosition); NOREF(aFilter); ReturnComNotImplemented(); #endif /* VBOX_WITH_USB */ }