VirtualBox

Changeset 60742 in vbox


Ignore:
Timestamp:
Apr 28, 2016 1:55:03 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
106933
Message:

Main/USBProxy{Service|Backend}: Rework interaction between thos two to be more sane than it currently is (calling into each other back and forth)

Location:
trunk/src/VBox/Main
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/USBProxyBackend.h

    r60108 r60742  
    6767    virtual int captureDevice(HostUSBDevice *aDevice);
    6868    virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    69     /** @todo unused */
    70     virtual void detachingDevice(HostUSBDevice *aDevice);
    7169    virtual int releaseDevice(HostUSBDevice *aDevice);
    7270    virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
     
    7472
    7573    static void freeDevice(PUSBDEVICE pDevice);
    76 
    77     HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    78                                   SessionMachinesList &llOpenedMachines,
    79                                   SessionMachine *aIgnoreMachine);
    80     bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
    81 
    82     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    83     virtual void deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
    84     virtual void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine);
    85     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    8674
    8775protected:
     
    9482    virtual int interruptWait(void);
    9583    virtual PUSBDEVICE getDevices(void);
    96     bool updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    9784    uint32_t incRef();
    9885    uint32_t decRef();
     
    10289    static void initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice);
    10390    static void freeDeviceMembers(PUSBDEVICE pDevice);
     91
     92    /**
     93     * Backend specific callback when a device was added.
     94     * (Currently only Linux uses it to adjust the udev polling).
     95     */
     96    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev);
    10497
    10598private:
     
    110103
    111104    static DECLCALLBACK(int) serviceThread(RTTHREAD Thread, void *pvUser);
     105
     106    void updateDeviceList(PUSBDEVICE pDevices);
    112107
    113108protected:
     
    126121    /** Reference counter which prevents the backend instance from being removed. */
    127122    uint32_t           m_cRefs;
     123    /** List of smart HostUSBDevice pointers. */
     124    typedef std::list<ComObjPtr<HostUSBDevice> > HostUSBDeviceList;
     125    /** List of the known USB devices for this backend. */
     126    HostUSBDeviceList  m_llDevices;
    128127};
    129128
     
    153152    virtual int captureDevice(HostUSBDevice *aDevice);
    154153    virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    155     /** @todo unused */
    156     virtual void detachingDevice(HostUSBDevice *aDevice);
    157154    virtual int releaseDevice(HostUSBDevice *aDevice);
    158155    virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
     
    164161    virtual void serviceThreadInit (void);
    165162    virtual void serviceThreadTerm (void);
    166     virtual bool updateDeviceState (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    167163
    168164private:
     
    208204    virtual int interruptWait(void);
    209205    virtual PUSBDEVICE getDevices(void);
    210     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    211     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
     206    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice);
    212207
    213208private:
     
    255250    virtual PUSBDEVICE getDevices(void);
    256251    int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
    257     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    258252
    259253private:
     
    302296    virtual int interruptWait(void);
    303297    virtual PUSBDEVICE getDevices(void);
    304     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    305298
    306299private:
     
    334327    virtual int interruptWait(void);
    335328    virtual PUSBDEVICE getDevices(void);
    336     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    337329
    338330private:
     
    365357    int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
    366358    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    367     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    368359
    369360private:
     
    413404    virtual int interruptWait(void);
    414405    virtual PUSBDEVICE getDevices(void);
    415     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    416406
    417407private:
  • trunk/src/VBox/Main/include/USBProxyService.h

    r60107 r60742  
    8383    typedef std::list< ComObjPtr<HostUSBDeviceFilter> > USBDeviceFilterList;
    8484
    85     void i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices);
    86     void i_getUSBFilters(USBDeviceFilterList *pGlobalFilters);
    87 
    8885    HRESULT i_loadSettings(const settings::USBDeviceSourcesList &llUSBDeviceSources);
    8986    HRESULT i_saveSettings(settings::USBDeviceSourcesList &llUSBDeviceSources);
     87
     88    void i_deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice);
     89    void i_deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
     90    void i_updateDeviceState(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice, bool fFakeUpdate);
    9091
    9192protected:
     
    101102
    102103private:
     104
     105    HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
     106                                  SessionMachinesList &llOpenedMachines,
     107                                  SessionMachine *aIgnoreMachine);
     108    bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
     109
     110    void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, bool fRunFilters, SessionMachine *aIgnoreMachine);
    103111
    104112    /** Pointer to the Host object. */
  • trunk/src/VBox/Main/src-server/USBProxyBackend.cpp

    r60159 r60742  
    8787    mTerminate = true;
    8888    m_pUsbProxyService = NULL;
     89    m_llDevices.clear();
    8990}
    9091
     
    140141    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    141142    return m_cRefs;
    142 }
    143 
    144 
    145 /**
    146  * Runs all the filters on the specified device.
    147  *
    148  * All filters mean global and active VM, with the exception of those
    149  * belonging to \a aMachine. If a global ignore filter matched or if
    150  * none of the filters matched, the device will be released back to
    151  * the host.
    152  *
    153  * The device calling us here will be in the HeldByProxy, Unused, or
    154  * Capturable state. The caller is aware that locks held might have
    155  * to be abandond because of IPC and that the device might be in
    156  * almost any state upon return.
    157  *
    158  *
    159  * @returns COM status code (only parameter & state checks will fail).
    160  * @param   aDevice         The USB device to apply filters to.
    161  * @param   aIgnoreMachine  The machine to ignore filters from (we've just
    162  *                          detached the device from this machine).
    163  *
    164  * @note    The caller is expected to own no locks.
    165  */
    166 HRESULT USBProxyBackend::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    167                                                SessionMachinesList &llOpenedMachines,
    168                                                SessionMachine *aIgnoreMachine)
    169 {
    170     LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
    171 
    172     /*
    173      * Verify preconditions.
    174      */
    175     AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
    176     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
    177 
    178     /*
    179      * Get the lists we'll iterate.
    180      */
    181     Host::USBDeviceFilterList globalFilters;
    182     m_pUsbProxyService->i_getUSBFilters(&globalFilters);
    183 
    184     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    185     AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    186     AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
    187                                                       aDevice->i_getStateName()), E_FAIL);
    188 
    189     /*
    190      * Run global filters filters first.
    191      */
    192     bool fHoldIt = false;
    193     for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
    194          it != globalFilters.end();
    195          ++it)
    196     {
    197         AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
    198         const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
    199         if (aDevice->i_isMatch(data))
    200         {
    201             USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
    202             (*it)->COMGETTER(Action)(&action);
    203             if (action == USBDeviceFilterAction_Ignore)
    204             {
    205                 /*
    206                  * Release the device to the host and we're done.
    207                  */
    208                 filterLock.release();
    209                 devLock.release();
    210                 alock.release();
    211                 aDevice->i_requestReleaseToHost();
    212                 return S_OK;
    213             }
    214             if (action == USBDeviceFilterAction_Hold)
    215             {
    216                 /*
    217                  * A device held by the proxy needs to be subjected
    218                  * to the machine filters.
    219                  */
    220                 fHoldIt = true;
    221                 break;
    222             }
    223             AssertMsgFailed(("action=%d\n", action));
    224         }
    225     }
    226     globalFilters.clear();
    227 
    228     /*
    229      * Run the per-machine filters.
    230      */
    231     for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
    232          it != llOpenedMachines.end();
    233          ++it)
    234     {
    235         ComObjPtr<SessionMachine> pMachine = *it;
    236 
    237         /* Skip the machine the device was just detached from. */
    238         if (    aIgnoreMachine
    239             &&  pMachine == aIgnoreMachine)
    240             continue;
    241 
    242         /* runMachineFilters takes care of checking the machine state. */
    243         devLock.release();
    244         alock.release();
    245         if (runMachineFilters(pMachine, aDevice))
    246         {
    247             LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
    248             return S_OK;
    249         }
    250         alock.acquire();
    251         devLock.acquire();
    252     }
    253 
    254     /*
    255      * No matching machine, so request hold or release depending
    256      * on global filter match.
    257      */
    258     devLock.release();
    259     alock.release();
    260     if (fHoldIt)
    261         aDevice->i_requestHold();
    262     else
    263         aDevice->i_requestReleaseToHost();
    264     return S_OK;
    265 }
    266 
    267 
    268 /**
    269  * Runs the USB filters of the machine on the device.
    270  *
    271  * If a match is found we will request capture for VM. This may cause
    272  * us to temporary abandon locks while doing IPC.
    273  *
    274  * @param   aMachine    Machine whose filters are to be run.
    275  * @param   aDevice     The USB device in question.
    276  * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
    277  *
    278  * @note    Locks several objects temporarily for reading or writing.
    279  */
    280 bool USBProxyBackend::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
    281 {
    282     LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
    283 
    284     /*
    285      * Validate preconditions.
    286      */
    287     AssertReturn(aMachine, false);
    288     AssertReturn(!isWriteLockOnCurrentThread(), false);
    289     AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
    290     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    291     /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
    292 
    293     /*
    294      * Do the job.
    295      */
    296     ULONG ulMaskedIfs;
    297     if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
    298     {
    299         /* try to capture the device */
    300         HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
    301         return SUCCEEDED(hrc)
    302             || hrc == E_UNEXPECTED /* bad device state, give up */;
    303     }
    304 
    305     return false;
    306143}
    307144
     
    361198    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    362199    incRef();
    363 }
    364 
    365 
    366 /**
    367  * The device is going to be detached from a VM.
    368  *
    369  * @param   aDevice     The device in question.
    370  *
    371  * @todo unused
    372  */
    373 void USBProxyBackend::detachingDevice(HostUSBDevice *aDevice)
    374 {
    375     NOREF(aDevice);
    376200}
    377201
     
    430254        {
    431255            PUSBDEVICE pDevices = getDevices();
    432             m_pUsbProxyService->i_updateDeviceList(this, pDevices);
     256            updateDeviceList(pDevices);
    433257
    434258            /*
     
    487311
    488312    /* Make sure there is no device from us in the list anymore. */
    489     m_pUsbProxyService->i_updateDeviceList(this, NULL);
     313    updateDeviceList(NULL);
    490314
    491315    return rc;
     
    518342
    519343        PUSBDEVICE pDevices = pThis->getDevices();
    520         pThis->m_pUsbProxyService->i_updateDeviceList(pThis, pDevices);
     344        pThis->updateDeviceList(pDevices);
    521345    }
    522346
     
    590414
    591415/**
    592  * Performs the required actions when a device has been added.
    593  *
    594  * This means things like running filters and subsequent capturing and
    595  * VM attaching. This may result in IPC and temporary lock abandonment.
    596  *
    597  * @param   aDevice     The device in question.
    598  * @param   aUSBDevice  The USB device structure.
    599  */
    600 void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
    601                                   SessionMachinesList &llOpenedMachines,
    602                                   PUSBDEVICE aUSBDevice)
    603 {
    604     /*
    605      * Validate preconditions.
    606      */
    607     AssertReturnVoid(!isWriteLockOnCurrentThread());
    608     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    609     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    610     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
    611                      (HostUSBDevice *)aDevice,
    612                      aDevice->i_getName().c_str(),
    613                      aDevice->i_getStateName(),
    614                      aDevice->i_getId().raw()));
    615 
    616     /*
    617      * Run filters on the device.
    618      */
    619     if (aDevice->i_isCapturableOrHeld())
    620     {
    621         devLock.release();
    622         HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
    623         AssertComRC(rc);
    624     }
    625 
    626     NOREF(aUSBDevice);
    627 }
    628 
    629 
    630 /**
    631  * Remove device notification hook for the OS specific code.
    632  *
    633  * This is means things like
    634  *
    635  * @param   aDevice     The device in question.
    636  */
    637 void USBProxyBackend::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
    638 {
    639     /*
    640      * Validate preconditions.
    641      */
    642     AssertReturnVoid(!isWriteLockOnCurrentThread());
    643     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    644     AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    645     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
    646                      (HostUSBDevice *)aDevice,
    647                      aDevice->i_getName().c_str(),
    648                      aDevice->i_getStateName(),
    649                      aDevice->i_getId().raw()));
    650 
    651     /*
    652      * Detach the device from any machine currently using it,
    653      * reset all data and uninitialize the device object.
    654      */
    655     devLock.release();
    656     aDevice->i_onPhysicalDetached();
    657 }
    658 
    659 
    660 /**
    661  * Implement fake capture, ++.
    662  *
    663  * @returns true if there is a state change.
    664  * @param   pDevice     The device in question.
    665  * @param   pUSBDevice  The USB device structure for the last enumeration.
    666  * @param   aRunFilters Whether or not to run filters.
    667  */
    668 bool USBProxyBackend::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    669                                             SessionMachine **aIgnoreMachine)
    670 {
    671     *aRunFilters = false;
    672     *aIgnoreMachine = NULL;
    673     AssertReturn(aDevice, false);
    674     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    675 
    676     /*
    677      * Just hand it to the device, it knows best what needs to be done.
    678      */
    679     return aDevice->i_updateStateFake(aUSBDevice, aRunFilters, aIgnoreMachine);
    680 }
    681 
    682 /**
    683416 * Increments the reference counter.
    684417 *
     
    703436    return --m_cRefs;
    704437}
    705 
    706 /**
    707  * Updates the device state.
    708  *
    709  * This is responsible for calling HostUSBDevice::updateState().
    710  *
    711  * @returns true if there is a state change.
    712  * @param   aDevice         The device in question.
    713  * @param   aUSBDevice      The USB device structure for the last enumeration.
    714  * @param   aRunFilters     Whether or not to run filters.
    715  * @param   aIgnoreMachine  Machine to ignore when running filters.
    716  */
    717 bool USBProxyBackend::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    718                                         SessionMachine **aIgnoreMachine)
    719 {
    720     AssertReturn(aDevice, false);
    721     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    722 
    723     return aDevice->i_updateState(aUSBDevice, aRunFilters, aIgnoreMachine);
    724 }
    725 
    726 
    727 /**
    728  * Handle a device which state changed in some significant way.
    729  *
    730  * This means things like running filters and subsequent capturing and
    731  * VM attaching. This may result in IPC and temporary lock abandonment.
    732  *
    733  * @param   aDevice         The device.
    734  * @param   pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters
    735  * @param   aIgnoreMachine  Machine to ignore when running filters.
    736  */
    737 void USBProxyBackend::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
    738                                     SessionMachine *aIgnoreMachine)
    739 {
    740     /*
    741      * Validate preconditions.
    742      */
    743     AssertReturnVoid(!isWriteLockOnCurrentThread());
    744     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    745     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    746     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
    747                      (HostUSBDevice *)aDevice,
    748                      aDevice->i_getName().c_str(),
    749                      aDevice->i_getStateName(),
    750                      aDevice->i_getId().raw(),
    751                      (pllOpenedMachines != NULL),       // used to be "bool aRunFilters"
    752                      aIgnoreMachine));
    753     devLock.release();
    754 
    755     /*
    756      * Run filters if requested to do so.
    757      */
    758     if (pllOpenedMachines)
    759     {
    760         HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine);
    761         AssertComRC(rc);
    762     }
    763 }
    764 
    765438
    766439
     
    808481}
    809482
     483void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev)
     484{
     485    /* Nothing to do. */
     486    NOREF(aDevice);
     487    NOREF(pDev);
     488}
    810489
    811490/**
     
    858537HRESULT USBProxyBackend::getType(com::Utf8Str &aType)
    859538{
    860     aType = Utf8Str("");
     539    aType = Utf8Str::Empty;
    861540    return S_OK;
    862541}
    863542
     543/**
     544 * Sort a list of USB devices.
     545 *
     546 * @returns Pointer to the head of the sorted doubly linked list.
     547 * @param   aDevices        Head pointer (can be both singly and doubly linked list).
     548 */
     549static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
     550{
     551    PUSBDEVICE pHead = NULL;
     552    PUSBDEVICE pTail = NULL;
     553    while (pDevices)
     554    {
     555        /* unlink head */
     556        PUSBDEVICE pDev = pDevices;
     557        pDevices = pDev->pNext;
     558        if (pDevices)
     559            pDevices->pPrev = NULL;
     560
     561        /* find location. */
     562        PUSBDEVICE pCur = pTail;
     563        while (     pCur
     564               &&   HostUSBDevice::i_compare(pCur, pDev) > 0)
     565            pCur = pCur->pPrev;
     566
     567        /* insert (after pCur) */
     568        pDev->pPrev = pCur;
     569        if (pCur)
     570        {
     571            pDev->pNext = pCur->pNext;
     572            pCur->pNext = pDev;
     573            if (pDev->pNext)
     574                pDev->pNext->pPrev = pDev;
     575            else
     576                pTail = pDev;
     577        }
     578        else
     579        {
     580            pDev->pNext = pHead;
     581            if (pHead)
     582                pHead->pPrev = pDev;
     583            else
     584                pTail = pDev;
     585            pHead = pDev;
     586        }
     587    }
     588
     589    LogFlowFuncLeave();
     590    return pHead;
     591}
     592
     593
     594/**
     595 * Process any relevant changes in the attached USB devices.
     596 *
     597 * This is called from any available USB proxy backends service thread when they discover
     598 * a change.
     599 */
     600void USBProxyBackend::updateDeviceList(PUSBDEVICE pDevices)
     601{
     602    LogFlowThisFunc(("\n"));
     603
     604    pDevices = sortDevices(pDevices);
     605
     606    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     607
     608    /*
     609     * Compare previous list with the new list of devices
     610     * and merge in any changes while notifying Host.
     611     */
     612    HostUSBDeviceList::iterator it = this->m_llDevices.begin();
     613    while (    it != m_llDevices.end()
     614           || pDevices)
     615    {
     616        ComObjPtr<HostUSBDevice> pHostDevice;
     617
     618        if (it != m_llDevices.end())
     619            pHostDevice = *it;
     620
     621        /*
     622         * Assert that the object is still alive (we still reference it in
     623         * the collection and we're the only one who calls uninit() on it.
     624         */
     625        AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
     626        AssertComRC(devCaller.rc());
     627
     628        /*
     629         * Lock the device object since we will read/write its
     630         * properties. All Host callbacks also imply the object is locked.
     631         */
     632        AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
     633                              COMMA_LOCKVAL_SRC_POS);
     634
     635        /* We should never get devices from other backends here. */
     636        Assert(pHostDevice.isNull() || pHostDevice->i_getUsbProxyBackend() == this);
     637
     638        /*
     639         * Compare.
     640         */
     641        int iDiff;
     642        if (pHostDevice.isNull())
     643            iDiff = 1;
     644        else
     645        {
     646            if (!pDevices)
     647                iDiff = -1;
     648            else
     649                iDiff = pHostDevice->i_compare(pDevices);
     650        }
     651        if (!iDiff)
     652        {
     653            /*
     654             * The device still there, update the state and move on. The PUSBDEVICE
     655             * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
     656             */
     657            PUSBDEVICE pCur = pDevices;
     658            pDevices = pDevices->pNext;
     659            pCur->pPrev = pCur->pNext = NULL;
     660
     661            devLock.release();
     662            alock.release();
     663            /** @todo: Add mthod for every backend indicating whether to use fake updating. */
     664#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
     665            m_pUsbProxyService->i_updateDeviceState(pHostDevice, pCur, true /* fFakeUpdate */);
     666#else
     667            m_pUsbProxyService->i_updateDeviceState(pHostDevice, pCur, false /* fFakeUpdate */);
     668#endif
     669            alock.acquire();
     670            ++it;
     671        }
     672        else
     673        {
     674            if (iDiff > 0)
     675            {
     676                /*
     677                 * Head of pDevices was attached.
     678                 */
     679                PUSBDEVICE pNew = pDevices;
     680                pDevices = pDevices->pNext;
     681                pNew->pPrev = pNew->pNext = NULL;
     682
     683                ComObjPtr<HostUSBDevice> NewObj;
     684                NewObj.createObject();
     685                NewObj->init(pNew, this);
     686                LogFlowThisFunc(("attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
     687                     (HostUSBDevice *)NewObj,
     688                     NewObj->i_getName().c_str(),
     689                     NewObj->i_getStateName(),
     690                     pNew,
     691                     pNew->idVendor,
     692                     pNew->idProduct,
     693                     pNew->pszProduct,
     694                     pNew->pszManufacturer));
     695
     696                m_llDevices.insert(it, NewObj);
     697
     698                devLock.release();
     699                alock.release();
     700                /* Do any backend specific work. */
     701                deviceAdded(NewObj, pNew);
     702                m_pUsbProxyService->i_deviceAdded(NewObj, pNew);
     703                alock.acquire();
     704            }
     705            else
     706            {
     707                /*
     708                 * Check if the device was actually detached or logically detached
     709                 * as the result of a re-enumeration.
     710                 */
     711                if (!pHostDevice->i_wasActuallyDetached())
     712                    ++it;
     713                else
     714                {
     715                    it = m_llDevices.erase(it);
     716                    devLock.release();
     717                    alock.release();
     718                    m_pUsbProxyService->i_deviceRemoved(pHostDevice);
     719                    LogFlowThisFunc(("detached %p {%s}\n",
     720                         (HostUSBDevice *)pHostDevice,
     721                         pHostDevice->i_getName().c_str()));
     722
     723                    /* from now on, the object is no more valid,
     724                     * uninitialize to avoid abuse */
     725                    devCaller.release();
     726                    pHostDevice->uninit();
     727                    alock.acquire();
     728                }
     729            }
     730        }
     731    } /* while */
     732
     733    LogFlowThisFunc(("returns void\n"));
     734}
     735
    864736/* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/src-server/USBProxyService.cpp

    r60551 r60742  
    349349        devLock.release();
    350350        alock.release();
    351         HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
     351        HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    352352        ComAssertComRC(hrc2);
    353353    }
     
    402402            USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
    403403            devLock.release();
    404             pUsbProxyBackend->runMachineFilters(aMachine, pHostDevice);
     404            runMachineFilters(aMachine, pHostDevice);
    405405        }
    406406    }
     
    469469                devLock.release();
    470470                alock.release();
    471                 HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
     471                HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    472472                ComAssertComRC(hrc2);
    473473                alock.acquire();
     
    485485
    486486/**
    487  * Sort a list of USB devices.
    488  *
    489  * @returns Pointer to the head of the sorted doubly linked list.
    490  * @param   aDevices        Head pointer (can be both singly and doubly linked list).
    491  */
    492 static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
    493 {
    494     PUSBDEVICE pHead = NULL;
    495     PUSBDEVICE pTail = NULL;
    496     while (pDevices)
    497     {
    498         /* unlink head */
    499         PUSBDEVICE pDev = pDevices;
    500         pDevices = pDev->pNext;
    501         if (pDevices)
    502             pDevices->pPrev = NULL;
    503 
    504         /* find location. */
    505         PUSBDEVICE pCur = pTail;
    506         while (     pCur
    507                &&   HostUSBDevice::i_compare(pCur, pDev) > 0)
    508             pCur = pCur->pPrev;
    509 
    510         /* insert (after pCur) */
    511         pDev->pPrev = pCur;
    512         if (pCur)
    513         {
    514             pDev->pNext = pCur->pNext;
    515             pCur->pNext = pDev;
    516             if (pDev->pNext)
    517                 pDev->pNext->pPrev = pDev;
    518             else
    519                 pTail = pDev;
    520         }
    521         else
    522         {
    523             pDev->pNext = pHead;
    524             if (pHead)
    525                 pHead->pPrev = pDev;
    526             else
    527                 pTail = pDev;
    528             pHead = pDev;
    529         }
    530     }
    531 
    532     LogFlowFuncLeave();
    533     return pHead;
    534 }
    535 
    536 
    537 /**
    538  * Process any relevant changes in the attached USB devices.
    539  *
    540  * This is called from any available USB proxy backends service thread when they discover
    541  * a change.
    542  */
    543 void USBProxyService::i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices)
    544 {
    545     LogFlowThisFunc(("\n"));
    546 
    547     pDevices = sortDevices(pDevices);
    548 
    549     // get a list of all running machines while we're outside the lock
    550     // (getOpenedMachines requests higher priority locks)
    551     SessionMachinesList llOpenedMachines;
    552     mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
    553 
    554     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    555 
    556     /*
    557      * Compare previous list with the new list of devices
    558      * and merge in any changes while notifying Host.
    559      */
    560     HostUSBDeviceList::iterator it = this->mDevices.begin();
    561     while (    it != mDevices.end()
    562             || pDevices)
    563     {
    564         ComObjPtr<HostUSBDevice> pHostDevice;
    565 
    566         if (it != mDevices.end())
    567             pHostDevice = *it;
    568 
    569         /*
    570          * Assert that the object is still alive (we still reference it in
    571          * the collection and we're the only one who calls uninit() on it.
    572          */
    573         AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
    574         AssertComRC(devCaller.rc());
    575 
    576         /*
    577          * Lock the device object since we will read/write its
    578          * properties. All Host callbacks also imply the object is locked.
    579          */
    580         AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
    581                               COMMA_LOCKVAL_SRC_POS);
    582 
    583         /* Skip all devices not belonging to the same backend. */
    584         if (   !pHostDevice.isNull()
    585             && pHostDevice->i_getUsbProxyBackend() != pUsbProxyBackend)
    586         {
    587             ++it;
    588             continue;
    589         }
    590 
    591         /*
    592          * Compare.
    593          */
    594         int iDiff;
    595         if (pHostDevice.isNull())
    596             iDiff = 1;
    597         else
    598         {
    599             if (!pDevices)
    600                 iDiff = -1;
    601             else
    602                 iDiff = pHostDevice->i_compare(pDevices);
    603         }
    604         if (!iDiff)
    605         {
    606             /*
    607              * The device still there, update the state and move on. The PUSBDEVICE
    608              * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
    609              */
    610             PUSBDEVICE pCur = pDevices;
    611             pDevices = pDevices->pNext;
    612             pCur->pPrev = pCur->pNext = NULL;
    613 
    614             bool fRunFilters = false;
    615             SessionMachine *pIgnoreMachine = NULL;
    616             devLock.release();
    617             alock.release();
    618             if (pUsbProxyBackend->updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
    619                 pUsbProxyBackend->deviceChanged(pHostDevice,
    620                                                 (fRunFilters ? &llOpenedMachines : NULL),
    621                                                 pIgnoreMachine);
    622             alock.acquire();
    623             ++it;
    624         }
    625         else
    626         {
    627             if (iDiff > 0)
    628             {
    629                 /*
    630                  * Head of pDevices was attached.
    631                  */
    632                 PUSBDEVICE pNew = pDevices;
    633                 pDevices = pDevices->pNext;
    634                 pNew->pPrev = pNew->pNext = NULL;
    635 
    636                 ComObjPtr<HostUSBDevice> NewObj;
    637                 NewObj.createObject();
    638                 NewObj->init(pNew, pUsbProxyBackend);
    639                 Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
    640                      (HostUSBDevice *)NewObj,
    641                      NewObj->i_getName().c_str(),
    642                      NewObj->i_getStateName(),
    643                      pNew,
    644                      pNew->idVendor,
    645                      pNew->idProduct,
    646                      pNew->pszProduct,
    647                      pNew->pszManufacturer));
    648 
    649                 mDevices.insert(it, NewObj);
    650 
    651                 devLock.release();
    652                 alock.release();
    653                 pUsbProxyBackend->deviceAdded(NewObj, llOpenedMachines, pNew);
    654                 alock.acquire();
    655             }
    656             else
    657             {
    658                 /*
    659                  * Check if the device was actually detached or logically detached
    660                  * as the result of a re-enumeration.
    661                  */
    662                 if (!pHostDevice->i_wasActuallyDetached())
    663                     ++it;
    664                 else
    665                 {
    666                     it = mDevices.erase(it);
    667                     devLock.release();
    668                     alock.release();
    669                     pUsbProxyBackend->deviceRemoved(pHostDevice);
    670                     Log(("USBProxyService::processChanges: detached %p {%s}\n",
    671                          (HostUSBDevice *)pHostDevice,
    672                          pHostDevice->i_getName().c_str()));
    673 
    674                     /* from now on, the object is no more valid,
    675                      * uninitialize to avoid abuse */
    676                     devCaller.release();
    677                     pHostDevice->uninit();
    678                     alock.acquire();
    679                 }
    680             }
    681         }
    682     } /* while */
    683 
    684     LogFlowThisFunc(("returns void\n"));
    685 }
    686 
    687 
    688 /**
    689  * Returns the global USB filter list stored in the Host object.
    690  *
    691  * @returns nothing.
    692  * @param   pGlobalFilters    Where to store the global filter list on success.
    693  */
    694 void USBProxyService::i_getUSBFilters(USBDeviceFilterList *pGlobalFilters)
    695 {
    696     mHost->i_getUSBFilters(pGlobalFilters);
    697 }
    698 
    699 
    700 /**
    701487 * Loads the given settings and constructs the additional USB device sources.
    702488 *
     
    749535    return S_OK;
    750536}
     537
     538/**
     539 * Performs the required actions when a device has been added.
     540 *
     541 * This means things like running filters and subsequent capturing and
     542 * VM attaching. This may result in IPC and temporary lock abandonment.
     543 *
     544 * @param   aDevice     The device in question.
     545 * @param   aUSBDevice  The USB device structure.
     546 */
     547void USBProxyService::i_deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
     548                                    PUSBDEVICE aUSBDevice)
     549{
     550    /*
     551     * Validate preconditions.
     552     */
     553    AssertReturnVoid(!isWriteLockOnCurrentThread());
     554    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
     555    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     556    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
     557    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
     558                     (HostUSBDevice *)aDevice,
     559                     aDevice->i_getName().c_str(),
     560                     aDevice->i_getStateName(),
     561                     aDevice->i_getId().raw()));
     562
     563    /* Add to our list. */
     564    PCUSBDEVICE pDev = aDevice->i_getUsbData();
     565    HostUSBDeviceList::iterator it = mDevices.begin();
     566    while (it != mDevices.end())
     567    {
     568        ComObjPtr<HostUSBDevice> pHostDevice = *it;
     569
     570        /* Assert that the object is still alive. */
     571        AutoCaller devCaller(pHostDevice);
     572        AssertComRC(devCaller.rc());
     573
     574        AutoWriteLock curLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
     575        if (   pHostDevice->i_getUsbProxyBackend() == aDevice->i_getUsbProxyBackend()
     576            && pHostDevice->i_compare(pDev) < 0)
     577            break;
     578
     579        it++;
     580    }
     581
     582    mDevices.insert(it, aDevice);
     583
     584    /*
     585     * Run filters on the device.
     586     */
     587    if (aDevice->i_isCapturableOrHeld())
     588    {
     589        devLock.release();
     590        alock.release();
     591        SessionMachinesList llOpenedMachines;
     592        mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
     593        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
     594        AssertComRC(rc);
     595    }
     596}
     597
     598/**
     599 * Remove device notification hook for the USB proxy service.
     600 *
     601 * @param   aDevice     The device in question.
     602 */
     603void USBProxyService::i_deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
     604{
     605    /*
     606     * Validate preconditions.
     607     */
     608    AssertReturnVoid(!isWriteLockOnCurrentThread());
     609    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
     610    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     611    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
     612    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
     613                     (HostUSBDevice *)aDevice,
     614                     aDevice->i_getName().c_str(),
     615                     aDevice->i_getStateName(),
     616                     aDevice->i_getId().raw()));
     617
     618    mDevices.remove(aDevice);
     619
     620    /*
     621     * Detach the device from any machine currently using it,
     622     * reset all data and uninitialize the device object.
     623     */
     624    devLock.release();
     625    alock.release();
     626    aDevice->i_onPhysicalDetached();
     627}
     628
     629/**
     630 * Updates the device state.
     631 *
     632 * This is responsible for calling HostUSBDevice::updateState().
     633 *
     634 * @returns true if there is a state change.
     635 * @param   aDevice         The device in question.
     636 * @param   aUSBDevice      The USB device structure for the last enumeration.
     637 * @param   fFakeUpdate     Flag whether to fake updating state.
     638 */
     639void USBProxyService::i_updateDeviceState(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice, bool fFakeUpdate)
     640{
     641    AssertReturnVoid(aDevice);
     642    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
     643
     644    bool fRunFilters = false;
     645    SessionMachine *pIgnoreMachine = NULL;
     646    bool fDevChanged = false;
     647    if (fFakeUpdate)
     648        fDevChanged = aDevice->i_updateStateFake(aUSBDevice, &fRunFilters, &pIgnoreMachine);
     649    else
     650        fDevChanged = aDevice->i_updateState(aUSBDevice, &fRunFilters, &pIgnoreMachine);
     651
     652    if (fDevChanged)
     653        deviceChanged(aDevice, fRunFilters, pIgnoreMachine);
     654}
     655
     656
     657/**
     658 * Handle a device which state changed in some significant way.
     659 *
     660 * This means things like running filters and subsequent capturing and
     661 * VM attaching. This may result in IPC and temporary lock abandonment.
     662 *
     663 * @param   aDevice         The device.
     664 * @param   fRunFilters     Flag whether to run filters.
     665 * @param   aIgnoreMachine  Machine to ignore when running filters.
     666 */
     667void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, bool fRunFilters,
     668                                    SessionMachine *aIgnoreMachine)
     669{
     670    /*
     671     * Validate preconditions.
     672     */
     673    AssertReturnVoid(!isWriteLockOnCurrentThread());
     674    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
     675    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
     676    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
     677                     (HostUSBDevice *)aDevice,
     678                     aDevice->i_getName().c_str(),
     679                     aDevice->i_getStateName(),
     680                     aDevice->i_getId().raw(),
     681                     fRunFilters,
     682                     aIgnoreMachine));
     683    devLock.release();
     684
     685    /*
     686     * Run filters if requested to do so.
     687     */
     688    if (fRunFilters)
     689    {
     690        SessionMachinesList llOpenedMachines;
     691        mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
     692        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, aIgnoreMachine);
     693        AssertComRC(rc);
     694    }
     695}
     696
     697
     698/**
     699 * Runs all the filters on the specified device.
     700 *
     701 * All filters mean global and active VM, with the exception of those
     702 * belonging to \a aMachine. If a global ignore filter matched or if
     703 * none of the filters matched, the device will be released back to
     704 * the host.
     705 *
     706 * The device calling us here will be in the HeldByProxy, Unused, or
     707 * Capturable state. The caller is aware that locks held might have
     708 * to be abandond because of IPC and that the device might be in
     709 * almost any state upon return.
     710 *
     711 *
     712 * @returns COM status code (only parameter & state checks will fail).
     713 * @param   aDevice         The USB device to apply filters to.
     714 * @param   aIgnoreMachine  The machine to ignore filters from (we've just
     715 *                          detached the device from this machine).
     716 *
     717 * @note    The caller is expected to own no locks.
     718 */
     719HRESULT USBProxyService::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
     720                                               SessionMachinesList &llOpenedMachines,
     721                                               SessionMachine *aIgnoreMachine)
     722{
     723    LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
     724
     725    /*
     726     * Verify preconditions.
     727     */
     728    AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
     729    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
     730
     731    /*
     732     * Get the lists we'll iterate.
     733     */
     734    Host::USBDeviceFilterList globalFilters;
     735    mHost->i_getUSBFilters(&globalFilters);
     736
     737    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     738    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
     739    AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
     740                                                      aDevice->i_getStateName()), E_FAIL);
     741
     742    /*
     743     * Run global filters filters first.
     744     */
     745    bool fHoldIt = false;
     746    for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
     747         it != globalFilters.end();
     748         ++it)
     749    {
     750        AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
     751        const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
     752        if (aDevice->i_isMatch(data))
     753        {
     754            USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
     755            (*it)->COMGETTER(Action)(&action);
     756            if (action == USBDeviceFilterAction_Ignore)
     757            {
     758                /*
     759                 * Release the device to the host and we're done.
     760                 */
     761                filterLock.release();
     762                devLock.release();
     763                alock.release();
     764                aDevice->i_requestReleaseToHost();
     765                return S_OK;
     766            }
     767            if (action == USBDeviceFilterAction_Hold)
     768            {
     769                /*
     770                 * A device held by the proxy needs to be subjected
     771                 * to the machine filters.
     772                 */
     773                fHoldIt = true;
     774                break;
     775            }
     776            AssertMsgFailed(("action=%d\n", action));
     777        }
     778    }
     779    globalFilters.clear();
     780
     781    /*
     782     * Run the per-machine filters.
     783     */
     784    for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
     785         it != llOpenedMachines.end();
     786         ++it)
     787    {
     788        ComObjPtr<SessionMachine> pMachine = *it;
     789
     790        /* Skip the machine the device was just detached from. */
     791        if (    aIgnoreMachine
     792            &&  pMachine == aIgnoreMachine)
     793            continue;
     794
     795        /* runMachineFilters takes care of checking the machine state. */
     796        devLock.release();
     797        alock.release();
     798        if (runMachineFilters(pMachine, aDevice))
     799        {
     800            LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
     801            return S_OK;
     802        }
     803        alock.acquire();
     804        devLock.acquire();
     805    }
     806
     807    /*
     808     * No matching machine, so request hold or release depending
     809     * on global filter match.
     810     */
     811    devLock.release();
     812    alock.release();
     813    if (fHoldIt)
     814        aDevice->i_requestHold();
     815    else
     816        aDevice->i_requestReleaseToHost();
     817    return S_OK;
     818}
     819
     820
     821/**
     822 * Runs the USB filters of the machine on the device.
     823 *
     824 * If a match is found we will request capture for VM. This may cause
     825 * us to temporary abandon locks while doing IPC.
     826 *
     827 * @param   aMachine    Machine whose filters are to be run.
     828 * @param   aDevice     The USB device in question.
     829 * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
     830 *
     831 * @note    Locks several objects temporarily for reading or writing.
     832 */
     833bool USBProxyService::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
     834{
     835    LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
     836
     837    /*
     838     * Validate preconditions.
     839     */
     840    AssertReturn(aMachine, false);
     841    AssertReturn(!isWriteLockOnCurrentThread(), false);
     842    AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
     843    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
     844    /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
     845
     846    /*
     847     * Do the job.
     848     */
     849    ULONG ulMaskedIfs;
     850    if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
     851    {
     852        /* try to capture the device */
     853        HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
     854        return SUCCEEDED(hrc)
     855            || hrc == E_UNEXPECTED /* bad device state, give up */;
     856    }
     857
     858    return false;
     859}
     860
    751861
    752862/**
  • trunk/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp

    r60107 r60742  
    222222
    223223
    224 /** @todo unused */
    225 void USBProxyBackendDarwin::detachingDevice(HostUSBDevice *aDevice)
    226 {
    227     NOREF(aDevice);
    228 }
    229 
    230 
    231 bool USBProxyBackendDarwin::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
    232 {
    233     AssertReturn(aDevice, false);
    234     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    235     /* Nothing special here so far, so fall back on parent. */
    236     return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    237 }
    238 
    239 
    240224int USBProxyBackendDarwin::wait(RTMSINTERVAL aMillies)
    241225{
  • trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp

    r60606 r60742  
    153153}
    154154
    155 
    156 bool USBProxyBackendFreeBSD::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    157                                                SessionMachine **aIgnoreMachine)
    158 {
    159     AssertReturn(aDevice, false);
    160     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    161 
    162     return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    163 }
    164 
    165 
    166 /**
    167  * A device was added
    168  *
    169  * See USBProxyService::deviceAdded for details.
    170  */
    171 void USBProxyBackendFreeBSD::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
    172                                          PUSBDEVICE aUSBDevice)
    173 {
    174     USBProxyBackend::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
    175 }
    176155
    177156int USBProxyBackendFreeBSD::wait(RTMSINTERVAL aMillies)
     
    227206}
    228207
     208
    229209PUSBDEVICE USBProxyBackendFreeBSD::getDevices(void)
    230210{
  • trunk/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp

    r60713 r60742  
    435435
    436436
    437 bool USBProxyBackendUsbIp::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    438                                              SessionMachine **aIgnoreMachine)
    439 {
    440     AssertReturn(aDevice, false);
    441     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    442     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    443     if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
    444         &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
    445         LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
    446                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
    447     devLock.release();
    448     return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    449 }
    450 
    451 
    452437int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
    453438{
     
    504489                if (fEventsRecv & RTPOLL_EVT_READ)
    505490                    rc = receiveData();
    506                 else if (fEventsRecv & RTPOLL_EVT_ERROR)
     491                if (   RT_SUCCESS(rc)
     492                    && (fEventsRecv & RTPOLL_EVT_ERROR))
    507493                    rc = VERR_NET_SHUTDOWN;
    508494
  • trunk/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp

    r60107 r60742  
    269269
    270270
    271 bool USBProxyBackendLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    272                                              SessionMachine **aIgnoreMachine)
    273 {
    274     AssertReturn(aDevice, false);
    275     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    276     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    277     if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
    278         &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
    279         LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
    280                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
    281     devLock.release();
    282     return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    283 }
    284 
    285 
    286271/**
    287272 * A device was added, we need to adjust mUdevPolls.
    288  *
    289  * See USBProxyService::deviceAdded for details.
    290  */
    291 void USBProxyBackendLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
    292                                        PUSBDEVICE aUSBDevice)
     273 */
     274void USBProxyBackendLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev)
    293275{
    294276    AssertReturnVoid(aDevice);
    295277    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    296278    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    297     if (aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST)
    298     {
    299         LogRel(("USBProxy: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
    300                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
     279    if (pDev->enmState == USBDEVICESTATE_USED_BY_HOST)
     280    {
     281        LogRel(("USBProxyBackendLinux: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
     282                pDev->idVendor, pDev->idProduct, pDev->pszAddress));
    301283        mUdevPolls = 10; /* (10 * 500ms = 5s) */
    302284    }
    303285
    304286    devLock.release();
    305     USBProxyBackend::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
    306287}
    307288
  • trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp

    r60156 r60742  
    460460
    461461
    462 bool USBProxyBackendSolaris::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    463                                                SessionMachine **aIgnoreMachine)
    464 {
    465     AssertReturn(aDevice, false);
    466     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    467     return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    468 }
    469 
    470462/**
    471463 * Wrapper called by walkDeviceNode.
  • trunk/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp

    r60107 r60742  
    227227
    228228
    229 bool USBProxyBackendWindows::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    230                                                SessionMachine **aIgnoreMachine)
    231 {
    232     AssertReturn(aDevice, false);
    233     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    234     /* Nothing special here so far, so fall back on parent */
    235     return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    236 }
    237 
    238 
    239229int USBProxyBackendWindows::wait(unsigned aMillies)
    240230{
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette