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;
}
Exemple #4
0
/**
 * 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 */
}