/** * 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; }
/** @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 */ }