VirtualBox

Changeset 59117 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 14, 2015 2:04:37 PM (9 years ago)
Author:
vboxsync
Message:

USB,Main: Rework USBProxyService. Split it into a USBProxyService and USBProxyBackend class, USBProxyService can use multiple USBProxyBackend instances as sources for USB devices to attach to a VM which will be used for USB/IP support. Change the PDM USB API to contain a backend parameter instead of a remote flag to indicate the USB backend to use for the given device.

Location:
trunk/src/VBox
Files:
19 edited
3 copied
6 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/USBProxyDevice.cpp

    r59089 r59117  
    4040static char g_szDummyName[] = "proxy xxxx:yyyy";
    4141
    42 
     42/**
     43 * Array of supported proxy backends.
     44 */
     45static PCUSBPROXYBACK g_aUsbProxies[] =
     46{
     47    &g_USBProxyDeviceHost,
     48    &g_USBProxyDeviceVRDP,
     49    &g_USBProxyDeviceUsbIp
     50};
    4351
    4452/* Synchronously obtain a standard USB descriptor for a device, used in order
     
    847855    AssertRCReturn(rc, rc);
    848856
    849     bool fRemote;
    850     rc = CFGMR3QueryBool(pCfg, "Remote", &fRemote);
     857    char szBackend[64];
     858    rc = CFGMR3QueryString(pCfg, "Backend", szBackend, sizeof(szBackend));
    851859    AssertRCReturn(rc, rc);
    852860
     
    858866     * Select backend and open the device.
    859867     */
    860     if (!fRemote)
    861         pThis->pOps = &g_USBProxyDeviceHost;
    862     else
    863         pThis->pOps = &g_USBProxyDeviceVRDP;
     868    rc = VERR_NOT_FOUND;
     869    for (unsigned i = 0; i < RT_ELEMENTS(g_aUsbProxies); i++)
     870    {
     871        if (!RTStrICmp(szBackend, g_aUsbProxies[i]->pszName))
     872        {
     873            pThis->pOps = g_aUsbProxies[i];
     874            rc = VINF_SUCCESS;
     875            break;
     876        }
     877    }
     878    if (RT_FAILURE(rc))
     879        return PDMUSB_SET_ERROR(pUsbIns, rc, N_("USBProxy: Failed to find backend"));
    864880
    865881    pThis->pvInstanceDataR3 = RTMemAllocZ(pThis->pOps->cbBackend);
  • trunk/src/VBox/Devices/USB/USBProxyDevice.h

    r58158 r59117  
    175175/** The remote desktop backend. */
    176176extern const USBPROXYBACK g_USBProxyDeviceVRDP;
     177/** The USB/IP backend. */
     178extern const USBPROXYBACK g_USBProxyDeviceUsbIp;
    177179
    178180#ifdef RDESKTOP
  • trunk/src/VBox/Main/Makefile.kmk

    r58885 r59117  
    449449ifdef VBOX_WITH_USB
    450450 ifdef VBOX_WITH_SYSFS_BY_DEFAULT
    451   src-server/linux/USBProxyServiceLinux.cpp_DEFS += VBOX_WITH_SYSFS_BY_DEFAULT
     451  src-server/linux/USBProxyBackendLinux.cpp_DEFS += VBOX_WITH_SYSFS_BY_DEFAULT
    452452 endif
    453453 VBoxSVC_SOURCES  += \
    454454        src-server/USBDeviceFilterImpl.cpp \
    455455        src-server/USBProxyService.cpp \
     456        src-server/USBProxyBackend.cpp \
     457        src-server/generic/USBProxyBackendUsbIp.cpp \
    456458        src-server/HostUSBDeviceImpl.cpp
    457  VBoxSVC_SOURCES.darwin  +=  src-server/darwin/USBProxyServiceDarwin.cpp
    458  VBoxSVC_SOURCES.linux   +=   src-server/linux/USBProxyServiceLinux.cpp
     459 VBoxSVC_SOURCES.darwin  +=  src-server/darwin/USBProxyBackendDarwin.cpp
     460 VBoxSVC_SOURCES.linux   +=   src-server/linux/USBProxyBackendLinux.cpp
    459461 VBoxSVC_SOURCES.linux   +=   src-server/linux/USBGetDevices.cpp
    460  VBoxSVC_SOURCES.os2     +=     src-server/os2/USBProxyServiceOs2.cpp
    461  VBoxSVC_SOURCES.solaris += src-server/solaris/USBProxyServiceSolaris.cpp
    462  VBoxSVC_SOURCES.win     +=     src-server/win/USBProxyServiceWindows.cpp
    463  VBoxSVC_SOURCES.freebsd += src-server/freebsd/USBProxyServiceFreeBSD.cpp
     462 VBoxSVC_SOURCES.os2     +=     src-server/os2/USBProxyBackendOs2.cpp
     463 VBoxSVC_SOURCES.solaris += src-server/solaris/USBProxyBackendSolaris.cpp
     464 VBoxSVC_SOURCES.win     +=     src-server/win/USBProxyBackendWindows.cpp
     465 VBoxSVC_SOURCES.freebsd += src-server/freebsd/USBProxyBackendFreeBSD.cpp
    464466endif
    465467
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r58677 r59117  
    1802118021    uuid="5915d179-83c7-4f2b-a323-9a97f46f4e29"
    1802218022    wsmap="managed"
    18023     reservedAttributes="4"
     18023    reservedAttributes="3"
    1802418024    >
    1802518025    <desc>
     
    1810218102        Whether the device is physically connected to a remote VRDE
    1810318103        client or to a local host machine.
     18104      </desc>
     18105    </attribute>
     18106
     18107    <attribute name="backend" type="wstring" readonly="yes">
     18108      <desc>
     18109        The backend which will be used to communicate with this device.
    1810418110      </desc>
    1810518111    </attribute>
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r58383 r59117  
    707707
    708708    static DECLCALLBACK(int) i_usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid,
    709                                                  bool aRemote, const char *aAddress, void *pvRemoteBackend,
     709                                                 const char *aBackend, const char *aAddress, void *pvRemoteBackend,
    710710                                                 USHORT aPortVersion, ULONG aMaskedIfs, const char *pszCaptureFilename);
    711711    static DECLCALLBACK(int) i_usbDetachCallback(Console *that, PUVM pUVM, PCRTUUID aUuid);
  • trunk/src/VBox/Main/include/HostUSBDeviceImpl.h

    r57994 r59117  
    2121#include "VirtualBoxBase.h"
    2222#include "USBDeviceFilterImpl.h"
    23 /* #include "USBProxyService.h" circular on Host/HostUSBDevice, the includer
    24  * must include this. */
    25 
    2623#include <VBox/usb.h>
    2724#include "Logging.h"
     
    2926
    3027class SessionMachine;
    31 class USBProxyService;
     28class USBProxyBackend;
    3229
    3330/**
     
    179176
    180177    // public initializer/uninitializer for internal purposes only
    181     HRESULT init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService);
     178    HRESULT init(PUSBDEVICE aUsb, USBProxyBackend *aUSBProxyBackend);
    182179    void uninit();
    183180
     
    206203    /** @note Must be called from under the object read lock. */
    207204    PCUSBDEVICE i_getUsbData() const { return mUsb; }
     205
     206    USBProxyBackend *i_getUsbProxyBackend() const { return mUSBProxyBackend; }
    208207
    209208    com::Utf8Str i_getName();
     
    227226                                   HostUSBDeviceState aPendingState = kHostUSBDeviceState_Invalid,
    228227                                   HostUSBDeviceSubState aSubState = kHostUSBDeviceSubState_Default);
     228
     229    void *i_getBackendUserData() { return m_pvBackendUser; }
     230    void i_setBackendUserData(void *pvBackendUser) { m_pvBackendUser = pvBackendUser; }
    229231
    230232protected:
     
    261263    HRESULT getName(com::Utf8Str &aName);
    262264    HRESULT getState(USBDeviceState_T *aState);
     265    HRESULT getBackend(com::Utf8Str &aBackend);
    263266
    264267
     
    289292    /** The machine the usb device is (being) attached to. */
    290293    ComObjPtr<SessionMachine> mMachine;
    291     /** Pointer to the USB Proxy Service instance. */
    292     USBProxyService *mUSBProxyService;
     294    /** Pointer to the USB Proxy Backend instance. */
     295    USBProxyBackend *mUSBProxyBackend;
    293296    /** Pointer to the USB Device structure owned by this device.
    294297     * Only used for host devices. */
     
    304307    /** The filename to capture the USB traffic to. */
    305308    com::Utf8Str mCaptureFilename;
    306 
    307     friend class USBProxyService;
    308 #ifdef RT_OS_SOLARIS
    309     friend class USBProxyServiceSolaris;
    310 
    311     /** One-shot filter id only for new code */
    312     void *mOneShotId;
    313 #endif
    314 #ifdef RT_OS_LINUX
    315     friend class USBProxyServiceLinux;
    316 #endif
    317 #ifdef RT_OS_DARWIN
    318     /** One-shot filter id. */
    319     void *mOneShotId;
    320 
    321     friend class USBProxyServiceDarwin;
    322 #endif
    323 #ifdef RT_OS_FreeBSD
    324     friend class USBProxyServiceFreeBSD;
    325 #endif
     309    /** Optional opaque user data assigned by the USB proxy backend owning the device. */
     310    void        *m_pvBackendUser;
    326311};
    327312
  • trunk/src/VBox/Main/include/RemoteUSBDeviceImpl.h

    r56584 r59117  
    7979    HRESULT getSpeed(USBConnectionSpeed_T *aSpeed);
    8080    HRESULT getRemote(BOOL *aRemote);
     81    HRESULT getBackend(com::Utf8Str &aBackend);
    8182
    8283    // wrapped IHostUSBDevice properties
     
    101102
    102103        const Utf8Str address;
     104        const Utf8Str backend;
    103105
    104106        const uint16_t port;
  • trunk/src/VBox/Main/include/USBDeviceImpl.h

    r56584 r59117  
    5959    HRESULT getSpeed(USBConnectionSpeed_T *aSpeed);
    6060    HRESULT getRemote(BOOL *aRemote);
     61    HRESULT getBackend(com::Utf8Str &aBackend);
    6162
    6263    struct Data
     
    8485        /** The host specific address of the device. */
    8586        const com::Utf8Str address;
     87        /** The device specific backend. */
     88        const com::Utf8Str backend;
    8689        /** The host port number. */
    8790        const USHORT port;
  • trunk/src/VBox/Main/include/USBProxyBackend.h

    r59043 r59117  
    11/* $Id$ */
    22/** @file
    3  * VirtualBox USB Proxy Service (base) class.
     3 * VirtualBox USB Proxy Backend (base) class.
    44 */
    55
    66/*
    7  * Copyright (C) 2005-2012 Oracle Corporation
     7 * Copyright (C) 2005-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1717
    1818
    19 #ifndef ____H_USBPROXYSERVICE
    20 #define ____H_USBPROXYSERVICE
     19#ifndef ____H_USBPROXYBACKEND
     20#define ____H_USBPROXYBACKEND
    2121
    2222#include <VBox/usb.h>
    2323#include <VBox/usbfilter.h>
     24
     25#include <iprt/socket.h>
     26#include <iprt/poll.h>
     27#include <iprt/semaphore.h>
    2428
    2529#include "VirtualBoxBase.h"
    2630#include "VirtualBoxImpl.h"
    2731#include "HostUSBDeviceImpl.h"
    28 class Host;
    29 
    30 /**
    31  * Base class for the USB Proxy service.
    32  */
    33 class USBProxyService
     32class USBProxyService;
     33
     34/**
     35 * Base class for the USB Proxy Backend.
     36 */
     37class USBProxyBackend
    3438    : public VirtualBoxTranslatable
    3539{
    3640public:
    37     USBProxyService(Host *aHost);
    38     virtual HRESULT init(void);
    39     virtual ~USBProxyService();
     41    USBProxyBackend(USBProxyService *pUsbProxyService);
     42    virtual int init(void);
     43    virtual ~USBProxyBackend();
    4044
    4145    /**
     
    5155
    5256    bool isActive(void);
    53     int getLastError(void);
    54     HRESULT getLastErrorMessage(BSTR *aError);
    5557
    5658    RWLockHandle *lockHandle() const;
    57 
    58     /** @name Host Interfaces
    59      * @{ */
    60     HRESULT getDeviceCollection(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices);
    61     /** @} */
    62 
    63     /** @name SessionMachine Interfaces
    64      * @{ */
    65     HRESULT captureDeviceForVM(SessionMachine *aMachine, IN_GUID aId, const com::Utf8Str &aCaptureFilename);
    66     HRESULT detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone);
    67     HRESULT autoCaptureDevicesForVM(SessionMachine *aMachine);
    68     HRESULT detachAllDevicesFromVM(SessionMachine *aMachine, bool aDone, bool aAbnormal);
    69     /** @} */
    7059
    7160    /** @name Interface for the USBController and the Host object.
     
    8574    /** @} */
    8675
     76    static void freeDevice(PUSBDEVICE pDevice);
     77
     78    HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
     79                                  SessionMachinesList &llOpenedMachines,
     80                                  SessionMachine *aIgnoreMachine);
     81    bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
     82
     83    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
     84    virtual void deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
     85    virtual void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine);
     86    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
     87
    8788protected:
    8889    int start(void);
     
    9495    virtual int interruptWait(void);
    9596    virtual PUSBDEVICE getDevices(void);
    96     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    97     virtual void deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
    98     virtual void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine);
    9997    bool updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    100     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    101 
    102     ComObjPtr<HostUSBDevice> findDeviceById(IN_GUID aId);
    10398
    10499    static HRESULT setError(HRESULT aResultCode, const char *aText, ...);
     
    106101    static void initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice);
    107102    static void freeDeviceMembers(PUSBDEVICE pDevice);
    108 public:
    109     static void freeDevice(PUSBDEVICE pDevice);
    110 
    111 private:
    112     HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    113                                   SessionMachinesList &llOpenedMachines,
    114                                   SessionMachine *aIgnoreMachine);
    115     bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
    116     void processChanges(void);
     103
     104private:
     105
    117106    static DECLCALLBACK(int) serviceThread(RTTHREAD Thread, void *pvUser);
    118107
    119108protected:
    120     /** Pointer to the Host object. */
    121     Host *mHost;
     109    /** Pointer to the owning USB Proxy Service object. */
     110    USBProxyService *m_pUsbProxyService;
    122111    /** Thread handle of the service thread. */
    123     RTTHREAD mThread;
     112    RTTHREAD         mThread;
    124113    /** Flag which stop() sets to cause serviceThread to return. */
    125     bool volatile mTerminate;
    126     /** VBox status code of the last failure.
    127      * (Only used by start(), stop() and the child constructors.) */
    128     int mLastError;
    129     /** Optional error message to complement mLastError. */
    130     Bstr mLastErrorMessage;
    131     /** List of smart HostUSBDevice pointers. */
    132     typedef std::list<ComObjPtr<HostUSBDevice> > HostUSBDeviceList;
    133     /** List of the known USB devices. */
    134     HostUSBDeviceList mDevices;
     114    bool volatile    mTerminate;
    135115};
    136116
     
    145125
    146126/**
    147  * The Darwin hosted USB Proxy Service.
    148  */
    149 class USBProxyServiceDarwin : public USBProxyService
    150 {
    151 public:
    152     USBProxyServiceDarwin(Host *aHost);
    153     HRESULT init(void);
    154     ~USBProxyServiceDarwin();
     127 * The Darwin hosted USB Proxy Backend.
     128 */
     129class USBProxyBackendDarwin : public USBProxyBackend
     130{
     131public:
     132    USBProxyBackendDarwin(USBProxyService *pUsbProxyService);
     133    int init(void);
     134    ~USBProxyBackendDarwin();
    155135
    156136    virtual void *insertFilter(PCUSBFILTER aFilter);
     
    194174
    195175/**
    196  * The Linux hosted USB Proxy Service.
    197  */
    198 class USBProxyServiceLinux
    199     : public USBProxyService
    200 {
    201 public:
    202     USBProxyServiceLinux(Host *aHost);
    203     HRESULT init(void);
    204     ~USBProxyServiceLinux();
     176 * The Linux hosted USB Proxy Backend.
     177 */
     178class USBProxyBackendLinux: public USBProxyBackend
     179{
     180public:
     181    USBProxyBackendLinux(USBProxyService *pUsbProxyService);
     182    int init(void);
     183    ~USBProxyBackendLinux();
    205184
    206185    virtual int captureDevice(HostUSBDevice *aDevice);
     
    246225
    247226/**
    248  * The Linux hosted USB Proxy Service.
    249  */
    250 class USBProxyServiceOs2 : public USBProxyService
    251 {
    252 public:
    253     USBProxyServiceOs2 (Host *aHost);
    254     /// @todo virtual HRESULT init(void);
    255     ~USBProxyServiceOs2();
     227 * The Linux hosted USB Proxy Backend.
     228 */
     229class USBProxyBackendOs2 : public USBProxyBackend
     230{
     231public:
     232    USBProxyBackendOs2 (USBProxyService *pUsbProxyService);
     233    /// @todo virtual int init(void);
     234    ~USBProxyBackendOs2();
    256235
    257236    virtual int captureDevice (HostUSBDevice *aDevice);
     
    288267
    289268/**
    290  * The Solaris hosted USB Proxy Service.
    291  */
    292 class USBProxyServiceSolaris : public USBProxyService
    293 {
    294 public:
    295     USBProxyServiceSolaris(Host *aHost);
    296     HRESULT init(void);
    297     ~USBProxyServiceSolaris();
     269 * The Solaris hosted USB Proxy Backend.
     270 */
     271class USBProxyBackendSolaris : public USBProxyBackend
     272{
     273public:
     274    USBProxyBackendSolaris(USBProxyService *pUsbProxyService);
     275    int init(void);
     276    ~USBProxyBackendSolaris();
    298277
    299278    virtual void *insertFilter (PCUSBFILTER aFilter);
     
    321300# ifdef RT_OS_WINDOWS
    322301/**
    323  * The Windows hosted USB Proxy Service.
    324  */
    325 class USBProxyServiceWindows : public USBProxyService
    326 {
    327 public:
    328     USBProxyServiceWindows(Host *aHost);
    329     HRESULT init(void);
    330     ~USBProxyServiceWindows();
     302 * The Windows hosted USB Proxy Backend.
     303 */
     304class USBProxyBackendWindows : public USBProxyBackend
     305{
     306public:
     307    USBProxyBackendWindows(USBProxyService *pUsbProxyService);
     308    int init(void);
     309    ~USBProxyBackendWindows();
    331310
    332311    virtual void *insertFilter (PCUSBFILTER aFilter);
     
    350329# ifdef RT_OS_FREEBSD
    351330/**
    352  * The FreeBSD hosted USB Proxy Service.
    353  */
    354 class USBProxyServiceFreeBSD : public USBProxyService
    355 {
    356 public:
    357     USBProxyServiceFreeBSD(Host *aHost);
    358     HRESULT init(void);
    359     ~USBProxyServiceFreeBSD();
     331 * The FreeBSD hosted USB Proxy Backend.
     332 */
     333class USBProxyBackendFreeBSD : public USBProxyBackend
     334{
     335public:
     336    USBProxyBackendFreeBSD(USBProxyService *pUsbProxyService);
     337    int init(void);
     338    ~USBProxyBackendFreeBSD();
    360339
    361340    virtual int captureDevice(HostUSBDevice *aDevice);
     
    377356# endif /* RT_OS_FREEBSD */
    378357
    379 #endif /* !____H_USBPROXYSERVICE */
    380 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
     358/**
     359 * USB/IP Proxy receive state.
     360 */
     361typedef enum USBIPRECVSTATE
     362{
     363    /** Invalid state. */
     364    kUsbIpRecvState_Invalid = 0,
     365    /** There is no request waiting for an answer. */
     366    kUsbIpRecvState_None,
     367    /** Waiting for the complete reception of UsbIpRetDevList. */
     368    kUsbIpRecvState_Hdr,
     369    /** Waiting for the complete reception of a UsbIpExportedDevice structure. */
     370    kUsbIpRecvState_ExportedDevice,
     371    /** Waiting for a complete reception a UsbIpDeviceInterface strucutre to skip. */
     372    kUsbIpRecvState_DeviceInterface,
     373    /** 32bit hack. */
     374    kUsbIpRecvState_32Bit_Hack = 0x7fffffff
     375} USBIPRECVSTATE;
     376/** Pointer to a USB/IP receive state enum. */
     377typedef USBIPRECVSTATE *PUSBIPRECVSTATE;
     378
     379struct UsbIpExportedDevice;
     380
     381/**
     382 * The USB/IP Proxy Backend.
     383 */
     384class USBProxyBackendUsbIp: public USBProxyBackend
     385{
     386public:
     387    USBProxyBackendUsbIp(USBProxyService *pUsbProxyService);
     388    int init(void);
     389    ~USBProxyBackendUsbIp();
     390
     391    virtual int captureDevice(HostUSBDevice *aDevice);
     392    virtual int releaseDevice(HostUSBDevice *aDevice);
     393
     394protected:
     395    virtual int wait(RTMSINTERVAL aMillies);
     396    virtual int interruptWait(void);
     397    virtual PUSBDEVICE getDevices(void);
     398    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
     399
     400private:
     401    int  updateDeviceList(bool *pfDeviceListChanged);
     402    bool hasDevListChanged(PUSBDEVICE pDevices);
     403    void freeDeviceList(PUSBDEVICE pHead);
     404    void resetRecvState();
     405    int  reconnect();
     406    void disconnect();
     407    int  startListExportedDevicesReq();
     408    void advanceState(USBIPRECVSTATE enmRecvState);
     409    int  receiveData();
     410    int  processData();
     411    int  addDeviceToList(UsbIpExportedDevice *pDev);
     412
     413    struct Data;            // opaque data struct, defined in USBProxyBackendUsbIp.cpp
     414    Data *m;
     415};
     416
     417#endif /* !____H_USBPROXYBACKEND */
     418
  • trunk/src/VBox/Main/include/USBProxyService.h

    r57990 r59117  
    2626#include "VirtualBoxImpl.h"
    2727#include "HostUSBDeviceImpl.h"
     28#include "USBProxyBackend.h"
    2829class Host;
    2930
     
    5253    bool isActive(void);
    5354    int getLastError(void);
    54     HRESULT getLastErrorMessage(BSTR *aError);
    5555
    5656    RWLockHandle *lockHandle() const;
     57
     58    /** @name Interface for the USBController and the Host object.
     59     * @{ */
     60    void *insertFilter(PCUSBFILTER aFilter);
     61    void removeFilter(void *aId);
     62    /** @} */
    5763
    5864    /** @name Host Interfaces
     
    6975    /** @} */
    7076
    71     /** @name Interface for the USBController and the Host object.
    72      * @{ */
    73     virtual void *insertFilter(PCUSBFILTER aFilter);
    74     virtual void removeFilter(void *aId);
    75     /** @} */
     77    typedef std::list< ComObjPtr<HostUSBDeviceFilter> > USBDeviceFilterList;
    7678
    77     /** @name Interfaces for the HostUSBDevice
    78      * @{ */
    79     virtual int captureDevice(HostUSBDevice *aDevice);
    80     virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    81     /** @todo unused */
    82     virtual void detachingDevice(HostUSBDevice *aDevice);
    83     virtual int releaseDevice(HostUSBDevice *aDevice);
    84     virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    85     /** @} */
     79    void i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices);
     80    void i_getUSBFilters(USBDeviceFilterList *pGlobalFiltes);
    8681
    8782protected:
    88     int start(void);
    89     int stop(void);
    90     virtual void serviceThreadInit(void);
    91     virtual void serviceThreadTerm(void);
    92 
    93     virtual int wait(RTMSINTERVAL aMillies);
    94     virtual int interruptWait(void);
    95     virtual PUSBDEVICE getDevices(void);
    96     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    97     virtual void deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
    98     virtual void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine);
    99     bool updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    100     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    101 
    10283    ComObjPtr<HostUSBDevice> findDeviceById(IN_GUID aId);
    10384
    10485    static HRESULT setError(HRESULT aResultCode, const char *aText, ...);
    10586
    106     static void initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice);
    107     static void freeDeviceMembers(PUSBDEVICE pDevice);
    108 public:
    109     static void freeDevice(PUSBDEVICE pDevice);
     87private:
    11088
    111 private:
    112     HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    113                                   SessionMachinesList &llOpenedMachines,
    114                                   SessionMachine *aIgnoreMachine);
    115     bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
    116     void processChanges(void);
    117     static DECLCALLBACK(int) serviceThread(RTTHREAD Thread, void *pvUser);
    118 
    119 protected:
    12089    /** Pointer to the Host object. */
    12190    Host *mHost;
    122     /** Thread handle of the service thread. */
    123     RTTHREAD mThread;
    124     /** Flag which stop() sets to cause serviceThread to return. */
    125     bool volatile mTerminate;
    126     /** VBox status code of the last failure.
    127      * (Only used by start(), stop() and the child constructors.) */
    128     int mLastError;
    129     /** Optional error message to complement mLastError. */
    130     Bstr mLastErrorMessage;
    13191    /** List of smart HostUSBDevice pointers. */
    13292    typedef std::list<ComObjPtr<HostUSBDevice> > HostUSBDeviceList;
    13393    /** List of the known USB devices. */
    13494    HostUSBDeviceList mDevices;
     95    /** List of USBProxyBackend pointers. */
     96    typedef std::list<USBProxyBackend *> USBProxyBackendList;
     97    /** List of active USB backends. */
     98    USBProxyBackendList mBackends;
     99    int                 mLastError;
    135100};
    136 
    137 
    138 # ifdef RT_OS_DARWIN
    139 #  include <VBox/param.h>
    140 #  undef PAGE_SHIFT
    141 #  undef PAGE_SIZE
    142 #  define OSType Carbon_OSType
    143 #  include <Carbon/Carbon.h>
    144 #  undef OSType
    145 
    146 /**
    147  * The Darwin hosted USB Proxy Service.
    148  */
    149 class USBProxyServiceDarwin : public USBProxyService
    150 {
    151 public:
    152     USBProxyServiceDarwin(Host *aHost);
    153     HRESULT init(void);
    154     ~USBProxyServiceDarwin();
    155 
    156     virtual void *insertFilter(PCUSBFILTER aFilter);
    157     virtual void removeFilter(void *aId);
    158 
    159     virtual int captureDevice(HostUSBDevice *aDevice);
    160     virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    161     /** @todo unused */
    162     virtual void detachingDevice(HostUSBDevice *aDevice);
    163     virtual int releaseDevice(HostUSBDevice *aDevice);
    164     virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    165 
    166 protected:
    167     virtual int wait(RTMSINTERVAL aMillies);
    168     virtual int interruptWait (void);
    169     virtual PUSBDEVICE getDevices (void);
    170     virtual void serviceThreadInit (void);
    171     virtual void serviceThreadTerm (void);
    172     virtual bool updateDeviceState (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    173 
    174 private:
    175     /** Reference to the runloop of the service thread.
    176      * This is NULL if the service thread isn't running. */
    177     CFRunLoopRef mServiceRunLoopRef;
    178     /** The opaque value returned by DarwinSubscribeUSBNotifications. */
    179     void *mNotifyOpaque;
    180     /** A hack to work around the problem with the usb device enumeration
    181      * not including newly attached devices. */
    182     bool mWaitABitNextTime;
    183     /** Whether we've successfully initialized the USBLib and should call USBLibTerm in the destructor. */
    184     bool mUSBLibInitialized;
    185 };
    186 # endif /* RT_OS_DARWIN */
    187 
    188 
    189 # ifdef RT_OS_LINUX
    190 #  include <stdio.h>
    191 #  ifdef VBOX_USB_WITH_SYSFS
    192 #   include <HostHardwareLinux.h>
    193 #  endif
    194 
    195 /**
    196  * The Linux hosted USB Proxy Service.
    197  */
    198 class USBProxyServiceLinux
    199     : public USBProxyService
    200 {
    201 public:
    202     USBProxyServiceLinux(Host *aHost);
    203     HRESULT init(void);
    204     ~USBProxyServiceLinux();
    205 
    206     virtual int captureDevice(HostUSBDevice *aDevice);
    207     virtual int releaseDevice(HostUSBDevice *aDevice);
    208 
    209 protected:
    210     int initUsbfs(void);
    211     int initSysfs(void);
    212     void doUsbfsCleanupAsNeeded(void);
    213     virtual int wait(RTMSINTERVAL aMillies);
    214     virtual int interruptWait(void);
    215     virtual PUSBDEVICE getDevices(void);
    216     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    217     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    218 
    219 private:
    220     int waitUsbfs(RTMSINTERVAL aMillies);
    221     int waitSysfs(RTMSINTERVAL aMillies);
    222 
    223 private:
    224     /** File handle to the '/proc/bus/usb/devices' file. */
    225     RTFILE mhFile;
    226     /** Pipe used to interrupt wait(), the read end. */
    227     RTPIPE mhWakeupPipeR;
    228     /** Pipe used to interrupt wait(), the write end. */
    229     RTPIPE mhWakeupPipeW;
    230     /** The root of usbfs. */
    231     Utf8Str mDevicesRoot;
    232     /** Whether we're using <mUsbfsRoot>/devices or /sys/whatever. */
    233     bool mUsingUsbfsDevices;
    234     /** Number of 500ms polls left to do. See usbDeterminState for details. */
    235     unsigned mUdevPolls;
    236 #  ifdef VBOX_USB_WITH_SYSFS
    237     /** Object used for polling for hotplug events from hal. */
    238     VBoxMainHotplugWaiter *mpWaiter;
    239 #  endif
    240 };
    241 # endif /* RT_OS_LINUX */
    242 
    243 
    244 # ifdef RT_OS_OS2
    245 #  include <usbcalls.h>
    246 
    247 /**
    248  * The Linux hosted USB Proxy Service.
    249  */
    250 class USBProxyServiceOs2 : public USBProxyService
    251 {
    252 public:
    253     USBProxyServiceOs2 (Host *aHost);
    254     /// @todo virtual HRESULT init(void);
    255     ~USBProxyServiceOs2();
    256 
    257     virtual int captureDevice (HostUSBDevice *aDevice);
    258     virtual int releaseDevice (HostUSBDevice *aDevice);
    259 
    260 protected:
    261     virtual int wait(RTMSINTERVAL aMillies);
    262     virtual int interruptWait(void);
    263     virtual PUSBDEVICE getDevices(void);
    264     int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
    265     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    266 
    267 private:
    268     /** The notification event semaphore */
    269     HEV mhev;
    270     /** The notification id. */
    271     USBNOTIFY mNotifyId;
    272     /** The usbcalls.dll handle. */
    273     HMODULE mhmod;
    274     /** UsbRegisterChangeNotification */
    275     APIRET (APIENTRY *mpfnUsbRegisterChangeNotification)(PUSBNOTIFY, HEV, HEV);
    276     /** UsbDeregisterNotification */
    277     APIRET (APIENTRY *mpfnUsbDeregisterNotification)(USBNOTIFY);
    278     /** UsbQueryNumberDevices */
    279     APIRET (APIENTRY *mpfnUsbQueryNumberDevices)(PULONG);
    280     /** UsbQueryDeviceReport */
    281     APIRET (APIENTRY *mpfnUsbQueryDeviceReport)(ULONG, PULONG, PVOID);
    282 };
    283 # endif /* RT_OS_LINUX */
    284 
    285 
    286 # ifdef RT_OS_SOLARIS
    287 #  include <libdevinfo.h>
    288 
    289 /**
    290  * The Solaris hosted USB Proxy Service.
    291  */
    292 class USBProxyServiceSolaris : public USBProxyService
    293 {
    294 public:
    295     USBProxyServiceSolaris(Host *aHost);
    296     HRESULT init(void);
    297     ~USBProxyServiceSolaris();
    298 
    299     virtual void *insertFilter (PCUSBFILTER aFilter);
    300     virtual void removeFilter (void *aID);
    301 
    302     virtual int captureDevice (HostUSBDevice *aDevice);
    303     virtual int releaseDevice (HostUSBDevice *aDevice);
    304     virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    305     virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
    306 
    307 protected:
    308     virtual int wait(RTMSINTERVAL aMillies);
    309     virtual int interruptWait(void);
    310     virtual PUSBDEVICE getDevices(void);
    311     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    312 
    313 private:
    314     RTSEMEVENT mNotifyEventSem;
    315     /** Whether we've successfully initialized the USBLib and should call USBLibTerm in the destructor. */
    316     bool mUSBLibInitialized;
    317 };
    318 #endif  /* RT_OS_SOLARIS */
    319 
    320 
    321 # ifdef RT_OS_WINDOWS
    322 /**
    323  * The Windows hosted USB Proxy Service.
    324  */
    325 class USBProxyServiceWindows : public USBProxyService
    326 {
    327 public:
    328     USBProxyServiceWindows(Host *aHost);
    329     HRESULT init(void);
    330     ~USBProxyServiceWindows();
    331 
    332     virtual void *insertFilter (PCUSBFILTER aFilter);
    333     virtual void removeFilter (void *aID);
    334 
    335     virtual int captureDevice (HostUSBDevice *aDevice);
    336     virtual int releaseDevice (HostUSBDevice *aDevice);
    337 
    338 protected:
    339     virtual int wait(RTMSINTERVAL aMillies);
    340     virtual int interruptWait(void);
    341     virtual PUSBDEVICE getDevices(void);
    342     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    343 
    344 private:
    345 
    346     HANDLE mhEventInterrupt;
    347 };
    348 # endif /* RT_OS_WINDOWS */
    349 
    350 # ifdef RT_OS_FREEBSD
    351 /**
    352  * The FreeBSD hosted USB Proxy Service.
    353  */
    354 class USBProxyServiceFreeBSD : public USBProxyService
    355 {
    356 public:
    357     USBProxyServiceFreeBSD(Host *aHost);
    358     HRESULT init(void);
    359     ~USBProxyServiceFreeBSD();
    360 
    361     virtual int captureDevice(HostUSBDevice *aDevice);
    362     virtual int releaseDevice(HostUSBDevice *aDevice);
    363 
    364 protected:
    365     int initUsbfs(void);
    366     int initSysfs(void);
    367     virtual int wait(RTMSINTERVAL aMillies);
    368     virtual int interruptWait(void);
    369     virtual PUSBDEVICE getDevices(void);
    370     int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
    371     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
    372     virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
    373 
    374 private:
    375     RTSEMEVENT mNotifyEventSem;
    376 };
    377 # endif /* RT_OS_FREEBSD */
    378101
    379102#endif /* !____H_USBPROXYSERVICE */
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r58414 r59117  
    86318631    ComAssertComRCRetRC(hrc);
    86328632
     8633    Bstr BstrBackend;
     8634    hrc = aHostDevice->COMGETTER(Backend)(BstrBackend.asOutParam());
     8635    ComAssertComRCRetRC(hrc);
     8636
     8637    Utf8Str Backend(BstrBackend);
     8638
    86338639    /* Get the VM handle. */
    86348640    SafeVMPtr ptrVM(this);
     
    86558661    int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
    86568662                               (PFNRT)i_usbAttachCallback, 10,
    8657                                this, ptrVM.rawUVM(), aHostDevice, uuid.raw(), fRemote,
     8663                               this, ptrVM.rawUVM(), aHostDevice, uuid.raw(), Backend.c_str(),
    86588664                               Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs,
    86598665                               aCaptureFilename.isEmpty() ? NULL : aCaptureFilename.c_str());
     
    87068712//static
    87078713DECLCALLBACK(int)
    8708 Console::i_usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote,
     8714Console::i_usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, const char *pszBackend,
    87098715                             const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs,
    87108716                             const char *pszCaptureFilename)
     
    87168722    AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
    87178723
    8718     int vrc = PDMR3UsbCreateProxyDevice(pUVM, aUuid, aRemote, aAddress, pvRemoteBackend,
     8724    int vrc = PDMR3UsbCreateProxyDevice(pUVM, aUuid, pszBackend, aAddress, pvRemoteBackend,
    87198725                                        aPortVersion == 3 ? VUSB_STDVER_30 :
    87208726                                        aPortVersion == 2 ? VUSB_STDVER_20 : VUSB_STDVER_11,
  • trunk/src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp

    r56584 r59117  
    7676    RTStrPrintf(id, sizeof(id), REMOTE_USB_BACKEND_PREFIX_S "0x%08X&0x%08X", pDevDesc->id, u32ClientId);
    7777    unconst(mData.address)      = id;
     78    RTStrPrintf(id, sizeof(id), "vrdp");
     79    unconst(mData.backend)      = id;
    7880
    7981    unconst(mData.port)         = pDevDesc->idPort;
     
    151153
    152154    unconst(mData.address).setNull();
     155    unconst(mData.backend).setNull();
    153156
    154157    unconst(mData.port) = 0;
     
    269272}
    270273
     274HRESULT RemoteUSBDevice::getBackend(com::Utf8Str &aBackend)
     275{
     276    /* this is const, no need to lock */
     277    aBackend = mData.backend;
     278
     279    return S_OK;
     280}
     281
    271282// IHostUSBDevice properties
    272283////////////////////////////////////////////////////////////////////////////////
  • trunk/src/VBox/Main/src-client/USBDeviceImpl.cpp

    r53297 r59117  
    8787    unconst(mData.address) = Utf8Str(tmp);
    8888
     89    hrc = aUSBDevice->COMGETTER(Backend)(bptr);
     90    ComAssertComRCRet(hrc, hrc);
     91    unconst(mData.backend) = Utf8Str(tmp);
     92
    8993    hrc = aUSBDevice->COMGETTER(Port)(&unconst(mData.port));
    9094    ComAssertComRCRet(hrc, hrc);
     
    137141
    138142    unconst(mData.address).setNull();
     143    unconst(mData.backend).setNull();
    139144
    140145    unconst(mData.port) = 0;
     
    306311}
    307312
     313/**
     314 * Returns the device specific backend.
     315 *
     316 * @returns COM status code
     317 * @param   aBackend          Where to put the return string.
     318 */
     319HRESULT OUSBDevice::getBackend(com::Utf8Str &aBackend)
     320{
     321    /* this is const, no need to lock */
     322    aBackend = mData.backend;
     323
     324    return S_OK;
     325}
     326
    308327// private methods
    309328/////////////////////////////////////////////////////////////////////////////
  • trunk/src/VBox/Main/src-server/HostImpl.cpp

    r58794 r59117  
    277277     * Create and initialize the USB Proxy Service.
    278278     */
    279 # if defined(RT_OS_DARWIN)
    280     m->pUSBProxyService = new USBProxyServiceDarwin(this);
    281 # elif defined(RT_OS_LINUX)
    282     m->pUSBProxyService = new USBProxyServiceLinux(this);
    283 # elif defined(RT_OS_OS2)
    284     m->pUSBProxyService = new USBProxyServiceOs2(this);
    285 # elif defined(RT_OS_SOLARIS)
    286     m->pUSBProxyService = new USBProxyServiceSolaris(this);
    287 # elif defined(RT_OS_WINDOWS)
    288     m->pUSBProxyService = new USBProxyServiceWindows(this);
    289 # elif defined(RT_OS_FREEBSD)
    290     m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
    291 # else
    292279    m->pUSBProxyService = new USBProxyService(this);
    293 # endif
    294280    hrc = m->pUSBProxyService->init();
    295281    AssertComRCReturn(hrc, hrc);
  • trunk/src/VBox/Main/src-server/HostUSBDeviceImpl.cpp

    r58016 r59117  
    2323#include "HostImpl.h"
    2424#include "VirtualBoxErrorInfoImpl.h"
    25 #include "USBProxyService.h"
     25#include "USBProxyBackend.h"
    2626#include "USBIdDatabase.h"
    2727
     
    3939HRESULT HostUSBDevice::FinalConstruct()
    4040{
    41     mUSBProxyService = NULL;
     41    mUSBProxyBackend = NULL;
    4242    mUsb = NULL;
    4343
     
    6161 *                              This structure is now fully owned by the HostUSBDevice object and will be
    6262 *                              freed when it is destructed.
    63  * @param   aUSBProxyService    Pointer to the USB Proxy Service object.
    64  */
    65 HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
     63 * @param   aUSBProxyBackend    Pointer to the USB Proxy Backend object owning the device.
     64 */
     65HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyBackend *aUSBProxyBackend)
    6666{
    6767    ComAssertRet(aUsb, E_INVALIDARG);
     
    9090
    9191    /* Other data members */
    92     mUSBProxyService = aUSBProxyService;
     92    mUSBProxyBackend = aUSBProxyBackend;
    9393    mUsb = aUsb;
    9494
     
    116116    if (mUsb != NULL)
    117117    {
    118         USBProxyService::freeDevice(mUsb);
     118        USBProxyBackend::freeDevice(mUsb);
    119119        mUsb = NULL;
    120120    }
    121121
    122     mUSBProxyService = NULL;
     122    mUSBProxyBackend = NULL;
    123123    mUniState = kHostUSBDeviceState_Invalid;
    124124}
     
    306306}
    307307
     308
     309HRESULT HostUSBDevice::getBackend(com::Utf8Str &aBackend)
     310{
     311    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     312
     313    aBackend = mUsb->pszBackend;
     314
     315    return S_OK;
     316}
    308317
    309318// public methods only for internal purposes
     
    448457    mCaptureFilename = aCaptureFilename;
    449458    alock.release();
    450     int rc = mUSBProxyService->captureDevice(this);
     459    int rc = mUSBProxyBackend->captureDevice(this);
    451460    if (RT_FAILURE(rc))
    452461    {
     
    707716#endif
    708717    alock.release();
    709     int rc = mUSBProxyService->releaseDevice(this);
     718    int rc = mUSBProxyBackend->releaseDevice(this);
    710719    if (RT_FAILURE(rc))
    711720    {
     
    760769#endif
    761770    alock.release();
    762     int rc = mUSBProxyService->captureDevice(this);
     771    int rc = mUSBProxyBackend->captureDevice(this);
    763772    if (RT_FAILURE(rc))
    764773    {
     
    980989int HostUSBDevice::i_compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach /*= false */)
    981990{
     991    if (strcmp(aDev1->pszBackend, aDev2->pszBackend))
     992    {
     993        return 1;
     994    }
     995
    982996    /*
    983997     * Things that stays the same everywhere.
     
    11521166        aDev->pNext = mUsb->pNext;
    11531167        aDev->pPrev = mUsb->pPrev;
    1154         USBProxyService::freeDevice(mUsb);
     1168        USBProxyBackend::freeDevice(mUsb);
    11551169        mUsb = aDev;
    11561170    }
     
    11941208                    case kHostUSBDeviceState_Capturing:
    11951209                        LogThisFunc(("{%s} capture failed! (#1)\n", mName));
    1196                         mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
     1210                        mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
    11971211                        *aRunFilters = i_failTransition(kHostUSBDeviceState_UsedByHost);
    11981212                        mMachine.setNull();
     
    12021216                    case kHostUSBDeviceState_ReleasingToHost:
    12031217                        LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
    1204                         mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
     1218                        mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
    12051219                        *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
    12061220                        break;
     
    12621276                    case kHostUSBDeviceState_Capturing:
    12631277                        LogThisFunc(("{%s} capture failed! (#2)\n", mName));
    1264                         mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
     1278                        mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
    12651279                        *aRunFilters = i_failTransition(kHostUSBDeviceState_Capturable);
    12661280                        mMachine.setNull();
     
    12701284                    case kHostUSBDeviceState_ReleasingToHost:
    12711285                        LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
    1272                         mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
     1286                        mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
    12731287                        *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
    12741288                        break;
     
    13301344                        {
    13311345                            LogThisFunc(("{%s} capture failed! (#3)\n", mName));
    1332                             mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
     1346                            mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
    13331347                            *aRunFilters = i_failTransition(kHostUSBDeviceState_Unused);
    13341348                            mMachine.setNull();
     
    13391353                    case kHostUSBDeviceState_ReleasingToHost:
    13401354                        LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
    1341                         mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
     1355                        mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
    13421356                        *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
    13431357                        break;
     
    13801394                    case kHostUSBDeviceState_Capturing:
    13811395                        LogThisFunc(("{%s} capture succeeded!\n", mName));
    1382                         mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
     1396                        mUSBProxyBackend->captureDeviceCompleted(this, true /* aSuccess */);
    13831397                        *aRunFilters = i_advanceTransition(true /* fast forward thru re-attach */);
    13841398
     
    13951409                    case kHostUSBDeviceState_ReleasingToHost:
    13961410                        LogThisFunc(("{%s} %s failed!\n", mName, i_getStateName()));
    1397                         mUSBProxyService->releaseDeviceCompleted(this, false /* aSuccess */);
     1411                        mUSBProxyBackend->releaseDeviceCompleted(this, false /* aSuccess */);
    13981412                        *aRunFilters = i_setState(kHostUSBDeviceState_HeldByProxy);
    13991413                        break;
     
    15101524                aDev->pNext = mUsb->pNext;
    15111525                aDev->pPrev = mUsb->pPrev;
    1512                 USBProxyService::freeDevice(mUsb);
     1526                USBProxyBackend::freeDevice(mUsb);
    15131527                mUsb = aDev;
    15141528            }
     
    15161530            /* call the completion method */
    15171531            if (enmState == kHostUSBDeviceState_Capturing)
    1518                 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
     1532                mUSBProxyBackend->captureDeviceCompleted(this, true /* aSuccess */);
    15191533            else
    1520                 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
     1534                mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
    15211535
    15221536            /* Take action if we're supposed to attach it to a VM. */
  • trunk/src/VBox/Main/src-server/USBProxyBackend.cpp

    r59043 r59117  
    1616 */
    1717
     18#include "USBProxyBackend.h"
    1819#include "USBProxyService.h"
    1920#include "HostUSBDeviceImpl.h"
     
    3738 * Initialize data members.
    3839 */
    39 USBProxyService::USBProxyService(Host *aHost)
    40     : mHost(aHost), mThread(NIL_RTTHREAD), mTerminate(false), mLastError(VINF_SUCCESS), mDevices()
    41 {
    42     LogFlowThisFunc(("aHost=%p\n", aHost));
     40USBProxyBackend::USBProxyBackend(USBProxyService *pUsbProxyService)
     41    : m_pUsbProxyService(pUsbProxyService), mThread(NIL_RTTHREAD), mTerminate(false)
     42{
     43    LogFlowThisFunc(("pUsbProxyService=%p\n", pUsbProxyService));
    4344}
    4445
     
    4748 * Stub needed as long as the class isn't virtual
    4849 */
    49 HRESULT USBProxyService::init(void)
    50 {
    51     return S_OK;
     50int USBProxyBackend::init(void)
     51{
     52    return VINF_SUCCESS;
    5253}
    5354
     
    5657 * Empty destructor.
    5758 */
    58 USBProxyService::~USBProxyService()
     59USBProxyBackend::~USBProxyBackend()
    5960{
    6061    LogFlowThisFunc(("\n"));
    6162    Assert(mThread == NIL_RTTHREAD);
    62     mDevices.clear();
    6363    mTerminate = true;
    64     mHost = NULL;
     64    m_pUsbProxyService = NULL;
    6565}
    6666
     
    7272 * @returns false if the service isn't running.
    7373 */
    74 bool USBProxyService::isActive(void)
     74bool USBProxyBackend::isActive(void)
    7575{
    7676    return mThread != NIL_RTTHREAD;
    77 }
    78 
    79 
    80 /**
    81  * Get last error.
    82  * Can be used to check why the proxy !isActive() upon construction.
    83  *
    84  * @returns VBox status code.
    85  */
    86 int USBProxyService::getLastError(void)
    87 {
    88     return mLastError;
    89 }
    90 
    91 
    92 /**
    93  * Get last error message.
    94  * Can be used to check why the proxy !isActive() upon construction as an
    95  * extension to getLastError().  May return a NULL error.
    96  *
    97  * @param
    98  * @returns VBox status code.
    99  */
    100 HRESULT USBProxyService::getLastErrorMessage(BSTR *aError)
    101 {
    102     AssertPtrReturn(aError, E_POINTER);
    103     mLastErrorMessage.cloneTo(aError);
    104     return S_OK;
    10577}
    10678
     
    11587 * @returns Lock handle.
    11688 */
    117 RWLockHandle *USBProxyService::lockHandle() const
    118 {
    119     return mHost->lockHandle();
    120 }
    121 
    122 
    123 /**
    124  * Gets the collection of USB devices, slave of Host::USBDevices.
    125  *
    126  * This is an interface for the HostImpl::USBDevices property getter.
    127  *
    128  *
    129  * @param   aUSBDevices     Where to store the pointer to the collection.
    130  *
    131  * @returns COM status code.
    132  *
    133  * @remarks The caller must own the write lock of the host object.
    134  */
    135 HRESULT USBProxyService::getDeviceCollection(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
    136 {
    137     AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
    138 
    139     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    140 
    141     aUSBDevices.resize(mDevices.size());
    142     size_t i = 0;
    143     for (HostUSBDeviceList::const_iterator it = mDevices.begin(); it != mDevices.end(); ++it, ++i)
    144         aUSBDevices[i] = *it;
    145 
    146     return S_OK;
    147 }
    148 
    149 
    150 /**
    151  * Request capture of a specific device.
    152  *
    153  * This is in an interface for SessionMachine::CaptureUSBDevice(), which is
    154  * an internal worker used by Console::AttachUSBDevice() from the VM process.
    155  *
    156  * When the request is completed, SessionMachine::onUSBDeviceAttach() will
    157  * be called for the given machine object.
    158  *
    159  *
    160  * @param   aMachine        The machine to attach the device to.
    161  * @param   aId             The UUID of the USB device to capture and attach.
    162  *
    163  * @returns COM status code and error info.
    164  *
    165  * @remarks This method may operate synchronously as well as asynchronously. In the
    166  *          former case it will temporarily abandon locks because of IPC.
    167  */
    168 HRESULT USBProxyService::captureDeviceForVM(SessionMachine *aMachine, IN_GUID aId, const com::Utf8Str &aCaptureFilename)
    169 {
    170     ComAssertRet(aMachine, E_INVALIDARG);
    171     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    172 
    173     /*
    174      * Translate the device id into a device object.
    175      */
    176     ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
    177     if (pHostDevice.isNull())
    178         return setError(E_INVALIDARG,
    179                         tr("The USB device with UUID {%RTuuid} is not currently attached to the host"), Guid(aId).raw());
    180 
    181     /*
    182      * Try to capture the device
    183      */
    184     alock.release();
    185     return pHostDevice->i_requestCaptureForVM(aMachine, true /* aSetError */, aCaptureFilename);
    186 }
    187 
    188 
    189 /**
    190  * Notification from VM process about USB device detaching progress.
    191  *
    192  * This is in an interface for SessionMachine::DetachUSBDevice(), which is
    193  * an internal worker used by Console::DetachUSBDevice() from the VM process.
    194  *
    195  * @param   aMachine        The machine which is sending the notification.
    196  * @param   aId             The UUID of the USB device is concerns.
    197  * @param   aDone           \a false for the pre-action notification (necessary
    198  *                          for advancing the device state to avoid confusing
    199  *                          the guest).
    200  *                          \a true for the post-action notification. The device
    201  *                          will be subjected to all filters except those of
    202  *                          of \a Machine.
    203  *
    204  * @returns COM status code.
    205  *
    206  * @remarks When \a aDone is \a true this method may end up doing IPC to other
    207  *          VMs when running filters. In these cases it will temporarily
    208  *          abandon its locks.
    209  */
    210 HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone)
    211 {
    212     LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n",
    213                      aMachine,
    214                      aMachine->i_getName().c_str(),
    215                      Guid(aId).raw(),
    216                      aDone));
    217 
    218     // get a list of all running machines while we're outside the lock
    219     // (getOpenedMachines requests locks which are incompatible with the lock of the machines list)
    220     SessionMachinesList llOpenedMachines;
    221     mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
    222 
    223     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    224 
    225     ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
    226     ComAssertRet(!pHostDevice.isNull(), E_FAIL);
    227     AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
    228 
    229     /*
    230      * Work the state machine.
    231      */
    232     LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n",
    233                      pHostDevice->i_getId().raw(), pHostDevice->i_getStateName(), aDone, pHostDevice->i_getName().c_str()));
    234     bool fRunFilters = false;
    235     HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters);
    236 
    237     /*
    238      * Run filters if necessary.
    239      */
    240     if (    SUCCEEDED(hrc)
    241         &&  fRunFilters)
    242     {
    243         Assert(aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull());
    244         devLock.release();
    245         alock.release();
    246         HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    247         ComAssertComRC(hrc2);
    248     }
    249     return hrc;
    250 }
    251 
    252 
    253 /**
    254  * Apply filters for the machine to all eligible USB devices.
    255  *
    256  * This is in an interface for SessionMachine::CaptureUSBDevice(), which
    257  * is an internal worker used by Console::AutoCaptureUSBDevices() from the
    258  * VM process at VM startup.
    259  *
    260  * Matching devices will be attached to the VM and may result IPC back
    261  * to the VM process via SessionMachine::onUSBDeviceAttach() depending
    262  * on whether the device needs to be captured or not. If capture is
    263  * required, SessionMachine::onUSBDeviceAttach() will be called
    264  * asynchronously by the USB proxy service thread.
    265  *
    266  * @param   aMachine        The machine to capture devices for.
    267  *
    268  * @returns COM status code, perhaps with error info.
    269  *
    270  * @remarks Temporarily locks this object, the machine object and some USB
    271  *          device, and the called methods will lock similar objects.
    272  */
    273 HRESULT USBProxyService::autoCaptureDevicesForVM(SessionMachine *aMachine)
    274 {
    275     LogFlowThisFunc(("aMachine=%p{%s}\n",
    276                      aMachine,
    277                      aMachine->i_getName().c_str()));
    278 
    279     /*
    280      * Make a copy of the list because we cannot hold the lock protecting it.
    281      * (This will not make copies of any HostUSBDevice objects, only reference them.)
    282      */
    283     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    284     HostUSBDeviceList ListCopy = mDevices;
    285     alock.release();
    286 
    287     for (HostUSBDeviceList::iterator it = ListCopy.begin();
    288          it != ListCopy.end();
    289          ++it)
    290     {
    291         ComObjPtr<HostUSBDevice> device = *it;
    292         AutoReadLock devLock(device COMMA_LOCKVAL_SRC_POS);
    293         if (   device->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
    294             || device->i_getUnistate() == kHostUSBDeviceState_Unused
    295             || device->i_getUnistate() == kHostUSBDeviceState_Capturable)
    296         {
    297             devLock.release();
    298             runMachineFilters(aMachine, device);
    299         }
    300     }
    301 
    302     return S_OK;
    303 }
    304 
    305 
    306 /**
    307  * Detach all USB devices currently attached to a VM.
    308  *
    309  * This is in an interface for SessionMachine::DetachAllUSBDevices(), which
    310  * is an internal worker used by Console::powerDown() from the VM process
    311  * at VM startup, and SessionMachine::uninit() at VM abend.
    312  *
    313  * This is, like #detachDeviceFromVM(), normally a two stage journey
    314  * where \a aDone indicates where we are. In addition we may be called
    315  * to clean up VMs that have abended, in which case there will be no
    316  * preparatory call. Filters will be applied to the devices in the final
    317  * call with the risk that we have to do some IPC when attaching them
    318  * to other VMs.
    319  *
    320  * @param   aMachine        The machine to detach devices from.
    321  *
    322  * @returns COM status code, perhaps with error info.
    323  *
    324  * @remarks Write locks the host object and may temporarily abandon
    325  *          its locks to perform IPC.
    326  */
    327 HRESULT USBProxyService::detachAllDevicesFromVM(SessionMachine *aMachine, bool aDone, bool aAbnormal)
    328 {
    329     // get a list of all running machines while we're outside the lock
    330     // (getOpenedMachines requests locks which are incompatible with the host object lock)
    331     SessionMachinesList llOpenedMachines;
    332     mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
    333 
    334     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    335 
    336     /*
    337      * Make a copy of the device list (not the HostUSBDevice objects, just
    338      * the list) since we may end up performing IPC and temporarily have
    339      * to abandon locks when applying filters.
    340      */
    341     HostUSBDeviceList ListCopy = mDevices;
    342 
    343     for (HostUSBDeviceList::iterator it = ListCopy.begin();
    344          it != ListCopy.end();
    345          ++it)
    346     {
    347         ComObjPtr<HostUSBDevice> pHostDevice = *it;
    348         AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
    349         if (pHostDevice->i_getMachine() == aMachine)
    350         {
    351             /*
    352              * Same procedure as in detachUSBDevice().
    353              */
    354             bool fRunFilters = false;
    355             HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters, aAbnormal);
    356             if (    SUCCEEDED(hrc)
    357                 &&  fRunFilters)
    358             {
    359                 Assert(   aDone
    360                        && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
    361                        && pHostDevice->i_getMachine().isNull());
    362                 devLock.release();
    363                 alock.release();
    364                 HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    365                 ComAssertComRC(hrc2);
    366                 alock.acquire();
    367             }
    368         }
    369     }
    370 
    371     return S_OK;
     89RWLockHandle *USBProxyBackend::lockHandle() const
     90{
     91    return m_pUsbProxyService->lockHandle();
    37292}
    37393
     
    394114 * @note    The caller is expected to own no locks.
    395115 */
    396 HRESULT USBProxyService::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
     116HRESULT USBProxyBackend::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    397117                                               SessionMachinesList &llOpenedMachines,
    398118                                               SessionMachine *aIgnoreMachine)
     
    415135    Host::USBDeviceFilterList globalFilters;
    416136
    417     mHost->i_getUSBFilters(&globalFilters);
     137    m_pUsbProxyService->i_getUSBFilters(&globalFilters);
    418138
    419139    /*
     
    508228 * @note    Locks several objects temporarily for reading or writing.
    509229 */
    510 bool USBProxyService::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
     230bool USBProxyBackend::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
    511231{
    512232    LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
     
    543263 * @return  ID of the inserted filter
    544264 */
    545 void *USBProxyService::insertFilter(PCUSBFILTER aFilter)
     265void *USBProxyBackend::insertFilter(PCUSBFILTER aFilter)
    546266{
    547267    // return non-NULL to fake success.
     
    556276 * @param   aId             ID of the filter to remove
    557277 */
    558 void USBProxyService::removeFilter(void *aId)
     278void USBProxyBackend::removeFilter(void *aId)
    559279{
    560280    NOREF(aId);
     
    568288 * @param   aDevice     The device in question.
    569289 */
    570 int USBProxyService::captureDevice(HostUSBDevice *aDevice)
     290int USBProxyBackend::captureDevice(HostUSBDevice *aDevice)
    571291{
    572292    NOREF(aDevice);
     
    584304 * @param   aSuccess    Whether it succeeded or failed.
    585305 */
    586 void USBProxyService::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
     306void USBProxyBackend::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
    587307{
    588308    NOREF(aDevice);
     
    598318 * @todo unused
    599319 */
    600 void USBProxyService::detachingDevice(HostUSBDevice *aDevice)
     320void USBProxyBackend::detachingDevice(HostUSBDevice *aDevice)
    601321{
    602322    NOREF(aDevice);
     
    610330 * @param   aDevice     The device in question.
    611331 */
    612 int USBProxyService::releaseDevice(HostUSBDevice *aDevice)
     332int USBProxyBackend::releaseDevice(HostUSBDevice *aDevice)
    613333{
    614334    NOREF(aDevice);
     
    626346 * @param   aSuccess    Whether it succeeded or failed.
    627347 */
    628 void USBProxyService::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
     348void USBProxyBackend::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
    629349{
    630350    NOREF(aDevice);
     
    642362 * @returns VBox status code.
    643363 */
    644 int USBProxyService::start(void)
     364int USBProxyBackend::start(void)
    645365{
    646366    int rc = VINF_SUCCESS;
     
    653373        if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED || RT_SUCCESS(rc))
    654374        {
    655             processChanges();
     375            PUSBDEVICE pDevices = getDevices();
     376            m_pUsbProxyService->i_updateDeviceList(this, pDevices);
    656377
    657378            /*
     
    659380             */
    660381            mTerminate = false;
    661             rc = RTThreadCreate(&mThread, USBProxyService::serviceThread, this,
     382            rc = RTThreadCreate(&mThread, USBProxyBackend::serviceThread, this,
    662383                                0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "USBPROXY");
    663384            AssertRC(rc);
     
    667388                mThread = NIL_RTTHREAD;
    668389        }
    669         mLastError = rc;
    670390    }
    671391    else
     
    680400 * @returns VBox status code.
    681401 */
    682 int USBProxyService::stop(void)
     402int USBProxyBackend::stop(void)
    683403{
    684404    int rc = VINF_SUCCESS;
     
    705425        }
    706426        else
    707         {
    708427            AssertRC(rc);
    709             mLastError = rc;
    710         }
    711428    }
    712429    else
     
    721438 *
    722439 * @param   Thread      The thread handle.
    723  * @param   pvUser      Pointer to the USBProxyService instance.
    724  */
    725 /*static*/ DECLCALLBACK(int) USBProxyService::serviceThread(RTTHREAD /* Thread */, void *pvUser)
    726 {
    727     USBProxyService *pThis = (USBProxyService *)pvUser;
     440 * @param   pvUser      Pointer to the USBProxyBackend instance.
     441 */
     442/*static*/ DECLCALLBACK(int) USBProxyBackend::serviceThread(RTTHREAD /* Thread */, void *pvUser)
     443{
     444    USBProxyBackend *pThis = (USBProxyBackend *)pvUser;
    728445    LogFlowFunc(("pThis=%p\n", pThis));
    729446    pThis->serviceThreadInit();
     
    740457        if (pThis->mTerminate)
    741458            break;
    742         pThis->processChanges();
     459
     460        PUSBDEVICE pDevices = pThis->getDevices();
     461        pThis->m_pUsbProxyService->i_updateDeviceList(pThis, pDevices);
    743462    }
    744463
     
    753472 * thread initialization.
    754473 *
    755  * The default implementation in USBProxyService just a dummy stub.
    756  */
    757 void USBProxyService::serviceThreadInit(void)
     474 * The default implementation in USBProxyBackend just a dummy stub.
     475 */
     476void USBProxyBackend::serviceThreadInit(void)
    758477{
    759478}
     
    764483 * thread termination.
    765484 */
    766 void USBProxyService::serviceThreadTerm(void)
     485void USBProxyBackend::serviceThreadTerm(void)
    767486{
    768487}
     
    772491 * Wait for a change in the USB devices attached to the host.
    773492 *
    774  * The default implementation in USBProxyService just a dummy stub.
     493 * The default implementation in USBProxyBackend just a dummy stub.
    775494 *
    776495 * @returns VBox status code.  VERR_INTERRUPTED and VERR_TIMEOUT are considered
     
    778497 * @param   aMillies    Number of milliseconds to wait.
    779498 */
    780 int USBProxyService::wait(RTMSINTERVAL aMillies)
     499int USBProxyBackend::wait(RTMSINTERVAL aMillies)
    781500{
    782501    return RTThreadSleep(RT_MIN(aMillies, 250));
     
    787506 * Interrupt any wait() call in progress.
    788507 *
    789  * The default implementation in USBProxyService just a dummy stub.
     508 * The default implementation in USBProxyBackend just a dummy stub.
    790509 *
    791510 * @returns VBox status code.
    792511 */
    793 int USBProxyService::interruptWait(void)
     512int USBProxyBackend::interruptWait(void)
    794513{
    795514    return VERR_NOT_IMPLEMENTED;
     
    798517
    799518/**
    800  * Sort a list of USB devices.
    801  *
    802  * @returns Pointer to the head of the sorted doubly linked list.
    803  * @param   aDevices        Head pointer (can be both singly and doubly linked list).
    804  */
    805 static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
    806 {
    807     PUSBDEVICE pHead = NULL;
    808     PUSBDEVICE pTail = NULL;
    809     while (pDevices)
    810     {
    811         /* unlink head */
    812         PUSBDEVICE pDev = pDevices;
    813         pDevices = pDev->pNext;
    814         if (pDevices)
    815             pDevices->pPrev = NULL;
    816 
    817         /* find location. */
    818         PUSBDEVICE pCur = pTail;
    819         while (     pCur
    820                &&   HostUSBDevice::i_compare(pCur, pDev) > 0)
    821             pCur = pCur->pPrev;
    822 
    823         /* insert (after pCur) */
    824         pDev->pPrev = pCur;
    825         if (pCur)
    826         {
    827             pDev->pNext = pCur->pNext;
    828             pCur->pNext = pDev;
    829             if (pDev->pNext)
    830                 pDev->pNext->pPrev = pDev;
    831             else
    832                 pTail = pDev;
    833         }
    834         else
    835         {
    836             pDev->pNext = pHead;
    837             if (pHead)
    838                 pHead->pPrev = pDev;
    839             else
    840                 pTail = pDev;
    841             pHead = pDev;
    842         }
    843     }
    844 
    845     LogFlowFuncLeave();
    846     return pHead;
    847 }
    848 
    849 
    850 /**
    851  * Process any relevant changes in the attached USB devices.
    852  *
    853  * Except for the first call, this is always running on the service thread.
    854  */
    855 void USBProxyService::processChanges(void)
    856 {
    857     LogFlowThisFunc(("\n"));
    858 
    859     /*
    860      * Get the sorted list of USB devices.
    861      */
    862     PUSBDEVICE pDevices = getDevices();
    863     pDevices = sortDevices(pDevices);
    864 
    865     // get a list of all running machines while we're outside the lock
    866     // (getOpenedMachines requests higher priority locks)
    867     SessionMachinesList llOpenedMachines;
    868     mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
    869 
    870     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    871 
    872     /*
    873      * Compare previous list with the new list of devices
    874      * and merge in any changes while notifying Host.
    875      */
    876     HostUSBDeviceList::iterator it = this->mDevices.begin();
    877     while (    it != mDevices.end()
    878             || pDevices)
    879     {
    880         ComObjPtr<HostUSBDevice> pHostDevice;
    881 
    882         if (it != mDevices.end())
    883             pHostDevice = *it;
    884 
    885         /*
    886          * Assert that the object is still alive (we still reference it in
    887          * the collection and we're the only one who calls uninit() on it.
    888          */
    889         AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
    890         AssertComRC(devCaller.rc());
    891 
    892         /*
    893          * Lock the device object since we will read/write its
    894          * properties. All Host callbacks also imply the object is locked.
    895          */
    896         AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
    897                               COMMA_LOCKVAL_SRC_POS);
    898 
    899         /*
    900          * Compare.
    901          */
    902         int iDiff;
    903         if (pHostDevice.isNull())
    904             iDiff = 1;
    905         else
    906         {
    907             if (!pDevices)
    908                 iDiff = -1;
    909             else
    910                 iDiff = pHostDevice->i_compare(pDevices);
    911         }
    912         if (!iDiff)
    913         {
    914             /*
    915              * The device still there, update the state and move on. The PUSBDEVICE
    916              * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
    917              */
    918             PUSBDEVICE pCur = pDevices;
    919             pDevices = pDevices->pNext;
    920             pCur->pPrev = pCur->pNext = NULL;
    921 
    922             bool fRunFilters = false;
    923             SessionMachine *pIgnoreMachine = NULL;
    924             devLock.release();
    925             alock.release();
    926             if (updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
    927                 deviceChanged(pHostDevice,
    928                               (fRunFilters ? &llOpenedMachines : NULL),
    929                               pIgnoreMachine);
    930             alock.acquire();
    931             ++it;
    932         }
    933         else
    934         {
    935             if (iDiff > 0)
    936             {
    937                 /*
    938                  * Head of pDevices was attached.
    939                  */
    940                 PUSBDEVICE pNew = pDevices;
    941                 pDevices = pDevices->pNext;
    942                 pNew->pPrev = pNew->pNext = NULL;
    943 
    944                 ComObjPtr<HostUSBDevice> NewObj;
    945                 NewObj.createObject();
    946                 NewObj->init(pNew, this);
    947                 Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
    948                      (HostUSBDevice *)NewObj,
    949                      NewObj->i_getName().c_str(),
    950                      NewObj->i_getStateName(),
    951                      pNew,
    952                      pNew->idVendor,
    953                      pNew->idProduct,
    954                      pNew->pszProduct,
    955                      pNew->pszManufacturer));
    956 
    957                 mDevices.insert(it, NewObj);
    958 
    959                 devLock.release();
    960                 alock.release();
    961                 deviceAdded(NewObj, llOpenedMachines, pNew);
    962                 alock.acquire();
    963             }
    964             else
    965             {
    966                 /*
    967                  * Check if the device was actually detached or logically detached
    968                  * as the result of a re-enumeration.
    969                  */
    970                 if (!pHostDevice->i_wasActuallyDetached())
    971                     ++it;
    972                 else
    973                 {
    974                     it = mDevices.erase(it);
    975                     devLock.release();
    976                     alock.release();
    977                     deviceRemoved(pHostDevice);
    978                     Log(("USBProxyService::processChanges: detached %p {%s}\n",
    979                          (HostUSBDevice *)pHostDevice,
    980                          pHostDevice->i_getName().c_str()));
    981 
    982                     /* from now on, the object is no more valid,
    983                      * uninitialize to avoid abuse */
    984                     devCaller.release();
    985                     pHostDevice->uninit();
    986                     alock.acquire();
    987                 }
    988             }
    989         }
    990     } /* while */
    991 
    992     LogFlowThisFunc(("returns void\n"));
    993 }
    994 
    995 
    996 /**
    997519 * Get a list of USB device currently attached to the host.
    998520 *
    999  * The default implementation in USBProxyService just a dummy stub.
     521 * The default implementation in USBProxyBackend just a dummy stub.
    1000522 *
    1001523 * @returns Pointer to a list of USB devices.
    1002524 *          The list nodes are freed individually by calling freeDevice().
    1003525 */
    1004 PUSBDEVICE USBProxyService::getDevices(void)
     526PUSBDEVICE USBProxyBackend::getDevices(void)
    1005527{
    1006528    return NULL;
     
    1017539 * @param   aUSBDevice  The USB device structure.
    1018540 */
    1019 void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
     541void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
    1020542                                  SessionMachinesList &llOpenedMachines,
    1021543                                  PUSBDEVICE aUSBDevice)
     
    1054576 * @param   aDevice     The device in question.
    1055577 */
    1056 void USBProxyService::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
     578void USBProxyBackend::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
    1057579{
    1058580    /*
     
    1085607 * @param   aRunFilters Whether or not to run filters.
    1086608 */
    1087 bool USBProxyService::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
     609bool USBProxyBackend::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    1088610                                            SessionMachine **aIgnoreMachine)
    1089611{
     
    1111633 * @param   aIgnoreMachine  Machine to ignore when running filters.
    1112634 */
    1113 bool USBProxyService::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
     635bool USBProxyBackend::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    1114636                                        SessionMachine **aIgnoreMachine)
    1115637{
     
    1131653 * @param   aIgnoreMachine  Machine to ignore when running filters.
    1132654 */
    1133 void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
     655void USBProxyBackend::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
    1134656                                    SessionMachine *aIgnoreMachine)
    1135657{
     
    1167689 */
    1168690/*static*/ void
    1169 USBProxyService::freeDeviceMembers(PUSBDEVICE pDevice)
     691USBProxyBackend::freeDeviceMembers(PUSBDEVICE pDevice)
    1170692{
    1171693    RTStrFree((char *)pDevice->pszManufacturer);
     
    1178700    RTStrFree((char *)pDevice->pszAddress);
    1179701    pDevice->pszAddress = NULL;
     702    RTStrFree((char *)pDevice->pszBackend);
     703    pDevice->pszBackend = NULL;
    1180704#ifdef RT_OS_WINDOWS
    1181705    RTStrFree(pDevice->pszAltAddress);
     
    1196720 */
    1197721/*static*/ void
    1198 USBProxyService::freeDevice(PUSBDEVICE pDevice)
     722USBProxyBackend::freeDevice(PUSBDEVICE pDevice)
    1199723{
    1200724    freeDeviceMembers(pDevice);
     
    1210734 */
    1211735/*static*/ void
    1212 USBProxyService::initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice)
    1213 {
    1214     PCUSBDEVICE pDev = aDevice->mUsb;
     736USBProxyBackend::initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice)
     737{
     738    PCUSBDEVICE pDev = aDevice->i_getUsbData();
    1215739    int vrc;
    1216740
     
    1241765
    1242766
    1243 /**
    1244  * Searches the list of devices (mDevices) for the given device.
    1245  *
    1246  *
    1247  * @returns Smart pointer to the device on success, NULL otherwise.
    1248  * @param   aId             The UUID of the device we're looking for.
    1249  */
    1250 ComObjPtr<HostUSBDevice> USBProxyService::findDeviceById(IN_GUID aId)
    1251 {
    1252     Guid Id(aId);
    1253     ComObjPtr<HostUSBDevice> Dev;
    1254     for (HostUSBDeviceList::iterator it = mDevices.begin();
    1255          it != mDevices.end();
    1256          ++it)
    1257         if ((*it)->i_getId() == Id)
    1258         {
    1259             Dev = (*it);
    1260             break;
    1261         }
    1262 
    1263     return Dev;
    1264 }
    1265 
    1266767/*static*/
    1267 HRESULT USBProxyService::setError(HRESULT aResultCode, const char *aText, ...)
     768HRESULT USBProxyBackend::setError(HRESULT aResultCode, const char *aText, ...)
    1268769{
    1269770    va_list va;
     
    1271772    HRESULT rc = VirtualBoxBase::setErrorInternal(aResultCode,
    1272773                                                    COM_IIDOF(IHost),
    1273                                                     "USBProxyService",
     774                                                    "USBProxyBackend",
    1274775                                                    Utf8StrFmt(aText, va),
    1275776                                                    false /* aWarning*/,
  • trunk/src/VBox/Main/src-server/USBProxyService.cpp

    r58170 r59117  
    3333#include <iprt/string.h>
    3434
     35/** Pair of a USB proxy backend and the opaque filter data assigned by the backend. */
     36typedef std::pair<USBProxyBackend *, void *> USBFilterPair;
     37/** List of USB filter pairs. */
     38typedef std::list<USBFilterPair> USBFilterList;
     39
     40/**
     41 * Data for a USB device filter.
     42 */
     43struct USBFilterData
     44{
     45    USBFilterData()
     46        : llUsbFilters()
     47    { }
     48
     49    USBFilterList llUsbFilters;
     50};
    3551
    3652/**
     
    3854 */
    3955USBProxyService::USBProxyService(Host *aHost)
    40     : mHost(aHost), mThread(NIL_RTTHREAD), mTerminate(false), mLastError(VINF_SUCCESS), mDevices()
     56    : mHost(aHost), mDevices(), mBackends()
    4157{
    4258    LogFlowThisFunc(("aHost=%p\n", aHost));
     
    4965HRESULT USBProxyService::init(void)
    5066{
     67    USBProxyBackend *pUsbProxyBackendHost;
     68# if defined(RT_OS_DARWIN)
     69    pUsbProxyBackendHost = new USBProxyBackendDarwin(this);
     70# elif defined(RT_OS_LINUX)
     71    pUsbProxyBackendHost = new USBProxyBackendLinux(this);
     72# elif defined(RT_OS_OS2)
     73    pUsbProxyBackendHost = new USBProxyBackendOs2(this);
     74# elif defined(RT_OS_SOLARIS)
     75    pUsbProxyBackendHost = new USBProxyBackendSolaris(this);
     76# elif defined(RT_OS_WINDOWS)
     77    pUsbProxyBackendHost = new USBProxyBackendWindows(this);
     78# elif defined(RT_OS_FREEBSD)
     79    pUsbProxyBackendHost = new USBProxyBackendFreeBSD(this);
     80# else
     81    pUsbProxyBackendHost = new USBProxyBackend(this);
     82# endif
     83    int vrc = pUsbProxyBackendHost->init();
     84    if (RT_FAILURE(vrc))
     85    {
     86        delete pUsbProxyBackendHost;
     87        mLastError = vrc;
     88    }
     89    else
     90        mBackends.push_back(pUsbProxyBackendHost);
     91
     92#if 0 /** @todo: Pass in the config. */
     93    pUsbProxyBackendHost = new USBProxyBackendUsbIp(this);
     94    hrc = pUsbProxyBackendHost->init();
     95    if (FAILED(hrc))
     96    {
     97        delete pUsbProxyBackendHost;
     98        return hrc;
     99    }
     100#endif
     101
     102    mBackends.push_back(pUsbProxyBackendHost);
    51103    return S_OK;
    52104}
     
    59111{
    60112    LogFlowThisFunc(("\n"));
    61     Assert(mThread == NIL_RTTHREAD);
    62113    mDevices.clear();
    63     mTerminate = true;
     114    mBackends.clear();
    64115    mHost = NULL;
    65116}
     
    74125bool USBProxyService::isActive(void)
    75126{
    76     return mThread != NIL_RTTHREAD;
     127    return mBackends.size() > 0;
    77128}
    78129
     
    87138{
    88139    return mLastError;
    89 }
    90 
    91 
    92 /**
    93  * Get last error message.
    94  * Can be used to check why the proxy !isActive() upon construction as an
    95  * extension to getLastError().  May return a NULL error.
    96  *
    97  * @param
    98  * @returns VBox status code.
    99  */
    100 HRESULT USBProxyService::getLastErrorMessage(BSTR *aError)
    101 {
    102     AssertPtrReturn(aError, E_POINTER);
    103     mLastErrorMessage.cloneTo(aError);
    104     return S_OK;
    105140}
    106141
     
    120155}
    121156
     157
     158void *USBProxyService::insertFilter(PCUSBFILTER aFilter)
     159{
     160    USBFilterData *pFilterData = new USBFilterData();
     161
     162    for (USBProxyBackendList::iterator it = mBackends.begin();
     163         it != mBackends.end();
     164         ++it)
     165    {
     166        USBProxyBackend *pUsbProxyBackend = *it;
     167        void *pvId = pUsbProxyBackend->insertFilter(aFilter);
     168
     169        pFilterData->llUsbFilters.push_back(USBFilterPair(pUsbProxyBackend, pvId));
     170    }
     171
     172    return pFilterData;
     173}
     174
     175void USBProxyService::removeFilter(void *aId)
     176{
     177    USBFilterData *pFilterData = (USBFilterData *)aId;
     178
     179    for (USBFilterList::iterator it = pFilterData->llUsbFilters.begin();
     180         it != pFilterData->llUsbFilters.end();
     181         ++it)
     182    {
     183        USBProxyBackend *pUsbProxyBackend = it->first;
     184        pUsbProxyBackend->removeFilter(it->second);
     185    }
     186
     187    pFilterData->llUsbFilters.clear();
     188    delete pFilterData;
     189}
    122190
    123191/**
     
    241309        &&  fRunFilters)
    242310    {
     311        USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
    243312        Assert(aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull());
    244313        devLock.release();
    245314        alock.release();
    246         HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
     315        HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    247316        ComAssertComRC(hrc2);
    248317    }
     
    289358         ++it)
    290359    {
    291         ComObjPtr<HostUSBDevice> device = *it;
    292         AutoReadLock devLock(device COMMA_LOCKVAL_SRC_POS);
    293         if (   device->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
    294             || device->i_getUnistate() == kHostUSBDeviceState_Unused
    295             || device->i_getUnistate() == kHostUSBDeviceState_Capturable)
    296         {
     360        ComObjPtr<HostUSBDevice> pHostDevice = *it;
     361        AutoReadLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
     362        if (   pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
     363            || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Unused
     364            || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Capturable)
     365        {
     366            USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
    297367            devLock.release();
    298             runMachineFilters(aMachine, device);
     368            pUsbProxyBackend->runMachineFilters(aMachine, pHostDevice);
    299369        }
    300370    }
     
    357427                &&  fRunFilters)
    358428            {
     429                USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
    359430                Assert(   aDone
    360431                       && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
     
    362433                devLock.release();
    363434                alock.release();
    364                 HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
     435                HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
    365436                ComAssertComRC(hrc2);
    366437                alock.acquire();
     
    373444
    374445
    375 /**
    376  * Runs all the filters on the specified device.
    377  *
    378  * All filters mean global and active VM, with the exception of those
    379  * belonging to \a aMachine. If a global ignore filter matched or if
    380  * none of the filters matched, the device will be released back to
    381  * the host.
    382  *
    383  * The device calling us here will be in the HeldByProxy, Unused, or
    384  * Capturable state. The caller is aware that locks held might have
    385  * to be abandond because of IPC and that the device might be in
    386  * almost any state upon return.
    387  *
    388  *
    389  * @returns COM status code (only parameter & state checks will fail).
    390  * @param   aDevice         The USB device to apply filters to.
    391  * @param   aIgnoreMachine  The machine to ignore filters from (we've just
    392  *                          detached the device from this machine).
    393  *
    394  * @note    The caller is expected to own no locks.
    395  */
    396 HRESULT USBProxyService::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
    397                                                SessionMachinesList &llOpenedMachines,
    398                                                SessionMachine *aIgnoreMachine)
    399 {
    400     LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
    401 
    402     /*
    403      * Verify preconditions.
    404      */
    405     AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
    406     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
    407     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    408     AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    409     AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
    410                                                       aDevice->i_getStateName()), E_FAIL);
    411 
    412     /*
    413      * Get the lists we'll iterate.
    414      */
    415     Host::USBDeviceFilterList globalFilters;
    416 
    417     mHost->i_getUSBFilters(&globalFilters);
    418 
    419     /*
    420      * Run global filters filters first.
    421      */
    422     bool fHoldIt = false;
    423     for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
    424          it != globalFilters.end();
    425          ++it)
    426     {
    427         AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
    428         const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
    429         if (aDevice->i_isMatch(data))
    430         {
    431             USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
    432             (*it)->COMGETTER(Action)(&action);
    433             if (action == USBDeviceFilterAction_Ignore)
    434             {
    435                 /*
    436                  * Release the device to the host and we're done.
    437                  */
    438                 filterLock.release();
    439                 devLock.release();
    440                 alock.release();
    441                 aDevice->i_requestReleaseToHost();
    442                 return S_OK;
    443             }
    444             if (action == USBDeviceFilterAction_Hold)
    445             {
    446                 /*
    447                  * A device held by the proxy needs to be subjected
    448                  * to the machine filters.
    449                  */
    450                 fHoldIt = true;
    451                 break;
    452             }
    453             AssertMsgFailed(("action=%d\n", action));
    454         }
    455     }
    456     globalFilters.clear();
    457 
    458     /*
    459      * Run the per-machine filters.
    460      */
    461     for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
    462          it != llOpenedMachines.end();
    463          ++it)
    464     {
    465         ComObjPtr<SessionMachine> pMachine = *it;
    466 
    467         /* Skip the machine the device was just detached from. */
    468         if (    aIgnoreMachine
    469             &&  pMachine == aIgnoreMachine)
    470             continue;
    471 
    472         /* runMachineFilters takes care of checking the machine state. */
    473         devLock.release();
    474         alock.release();
    475         if (runMachineFilters(pMachine, aDevice))
    476         {
    477             LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
    478             return S_OK;
    479         }
    480         alock.acquire();
    481         devLock.acquire();
    482     }
    483 
    484     /*
    485      * No matching machine, so request hold or release depending
    486      * on global filter match.
    487      */
    488     devLock.release();
    489     alock.release();
    490     if (fHoldIt)
    491         aDevice->i_requestHold();
    492     else
    493         aDevice->i_requestReleaseToHost();
    494     return S_OK;
    495 }
    496 
    497 
    498 /**
    499  * Runs the USB filters of the machine on the device.
    500  *
    501  * If a match is found we will request capture for VM. This may cause
    502  * us to temporary abandon locks while doing IPC.
    503  *
    504  * @param   aMachine    Machine whose filters are to be run.
    505  * @param   aDevice     The USB device in question.
    506  * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
    507  *
    508  * @note    Locks several objects temporarily for reading or writing.
    509  */
    510 bool USBProxyService::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
    511 {
    512     LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
    513 
    514     /*
    515      * Validate preconditions.
    516      */
    517     AssertReturn(aMachine, false);
    518     AssertReturn(!isWriteLockOnCurrentThread(), false);
    519     AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
    520     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    521     /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
    522 
    523     /*
    524      * Do the job.
    525      */
    526     ULONG ulMaskedIfs;
    527     if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
    528     {
    529         /* try to capture the device */
    530         HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
    531         return SUCCEEDED(hrc)
    532             || hrc == E_UNEXPECTED /* bad device state, give up */;
    533     }
    534 
    535     return false;
    536 }
    537 
    538 
    539 /**
    540  * A filter was inserted / loaded.
    541  *
    542  * @param   aFilter         Pointer to the inserted filter.
    543  * @return  ID of the inserted filter
    544  */
    545 void *USBProxyService::insertFilter(PCUSBFILTER aFilter)
    546 {
    547     // return non-NULL to fake success.
    548     NOREF(aFilter);
    549     return (void *)1;
    550 }
    551 
    552 
    553 /**
    554  * A filter was removed.
    555  *
    556  * @param   aId             ID of the filter to remove
    557  */
    558 void USBProxyService::removeFilter(void *aId)
    559 {
    560     NOREF(aId);
    561 }
    562 
    563 
    564 /**
    565  * A VM is trying to capture a device, do necessary preparations.
    566  *
    567  * @returns VBox status code.
    568  * @param   aDevice     The device in question.
    569  */
    570 int USBProxyService::captureDevice(HostUSBDevice *aDevice)
    571 {
    572     NOREF(aDevice);
    573     return VERR_NOT_IMPLEMENTED;
    574 }
    575 
    576 
    577 /**
    578  * Notification that an async captureDevice() operation completed.
    579  *
    580  * This is used by the proxy to release temporary filters.
    581  *
    582  * @returns VBox status code.
    583  * @param   aDevice     The device in question.
    584  * @param   aSuccess    Whether it succeeded or failed.
    585  */
    586 void USBProxyService::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
    587 {
    588     NOREF(aDevice);
    589     NOREF(aSuccess);
    590 }
    591 
    592 
    593 /**
    594  * The device is going to be detached from a VM.
    595  *
    596  * @param   aDevice     The device in question.
    597  *
    598  * @todo unused
    599  */
    600 void USBProxyService::detachingDevice(HostUSBDevice *aDevice)
    601 {
    602     NOREF(aDevice);
    603 }
    604 
    605 
    606 /**
    607  * A VM is releasing a device back to the host.
    608  *
    609  * @returns VBox status code.
    610  * @param   aDevice     The device in question.
    611  */
    612 int USBProxyService::releaseDevice(HostUSBDevice *aDevice)
    613 {
    614     NOREF(aDevice);
    615     return VERR_NOT_IMPLEMENTED;
    616 }
    617 
    618 
    619 /**
    620  * Notification that an async releaseDevice() operation completed.
    621  *
    622  * This is used by the proxy to release temporary filters.
    623  *
    624  * @returns VBox status code.
    625  * @param   aDevice     The device in question.
    626  * @param   aSuccess    Whether it succeeded or failed.
    627  */
    628 void USBProxyService::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
    629 {
    630     NOREF(aDevice);
    631     NOREF(aSuccess);
    632 }
    633 
    634 
    635446// Internals
    636447/////////////////////////////////////////////////////////////////////////////
    637 
    638 
    639 /**
    640  * Starts the service.
    641  *
    642  * @returns VBox status code.
    643  */
    644 int USBProxyService::start(void)
    645 {
    646     int rc = VINF_SUCCESS;
    647     if (mThread == NIL_RTTHREAD)
    648     {
    649         /*
    650          * Force update before starting the poller thread.
    651          */
    652         rc = wait(0);
    653         if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED || RT_SUCCESS(rc))
    654         {
    655             processChanges();
    656 
    657             /*
    658              * Create the poller thread which will look for changes.
    659              */
    660             mTerminate = false;
    661             rc = RTThreadCreate(&mThread, USBProxyService::serviceThread, this,
    662                                 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "USBPROXY");
    663             AssertRC(rc);
    664             if (RT_SUCCESS(rc))
    665                 LogFlowThisFunc(("started mThread=%RTthrd\n", mThread));
    666             else
    667                 mThread = NIL_RTTHREAD;
    668         }
    669         mLastError = rc;
    670     }
    671     else
    672         LogFlowThisFunc(("already running, mThread=%RTthrd\n", mThread));
    673     return rc;
    674 }
    675 
    676 
    677 /**
    678  * Stops the service.
    679  *
    680  * @returns VBox status code.
    681  */
    682 int USBProxyService::stop(void)
    683 {
    684     int rc = VINF_SUCCESS;
    685     if (mThread != NIL_RTTHREAD)
    686     {
    687         /*
    688          * Mark the thread for termination and kick it.
    689          */
    690         ASMAtomicXchgSize(&mTerminate, true);
    691         rc = interruptWait();
    692         AssertRC(rc);
    693 
    694         /*
    695          * Wait for the thread to finish and then update the state.
    696          */
    697         rc = RTThreadWait(mThread, 60000, NULL);
    698         if (rc == VERR_INVALID_HANDLE)
    699             rc = VINF_SUCCESS;
    700         if (RT_SUCCESS(rc))
    701         {
    702             LogFlowThisFunc(("stopped mThread=%RTthrd\n", mThread));
    703             mThread = NIL_RTTHREAD;
    704             mTerminate = false;
    705         }
    706         else
    707         {
    708             AssertRC(rc);
    709             mLastError = rc;
    710         }
    711     }
    712     else
    713         LogFlowThisFunc(("not active\n"));
    714 
    715     return rc;
    716 }
    717 
    718 
    719 /**
    720  * The service thread created by start().
    721  *
    722  * @param   Thread      The thread handle.
    723  * @param   pvUser      Pointer to the USBProxyService instance.
    724  */
    725 /*static*/ DECLCALLBACK(int) USBProxyService::serviceThread(RTTHREAD /* Thread */, void *pvUser)
    726 {
    727     USBProxyService *pThis = (USBProxyService *)pvUser;
    728     LogFlowFunc(("pThis=%p\n", pThis));
    729     pThis->serviceThreadInit();
    730     int rc = VINF_SUCCESS;
    731 
    732     /*
    733      * Processing loop.
    734      */
    735     for (;;)
    736     {
    737         rc = pThis->wait(RT_INDEFINITE_WAIT);
    738         if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT)
    739             break;
    740         if (pThis->mTerminate)
    741             break;
    742         pThis->processChanges();
    743     }
    744 
    745     pThis->serviceThreadTerm();
    746     LogFlowFunc(("returns %Rrc\n", rc));
    747     return rc;
    748 }
    749 
    750 
    751 /**
    752  * First call made on the service thread, use it to do
    753  * thread initialization.
    754  *
    755  * The default implementation in USBProxyService just a dummy stub.
    756  */
    757 void USBProxyService::serviceThreadInit(void)
    758 {
    759 }
    760 
    761 
    762 /**
    763  * Last call made on the service thread, use it to do
    764  * thread termination.
    765  */
    766 void USBProxyService::serviceThreadTerm(void)
    767 {
    768 }
    769 
    770 
    771 /**
    772  * Wait for a change in the USB devices attached to the host.
    773  *
    774  * The default implementation in USBProxyService just a dummy stub.
    775  *
    776  * @returns VBox status code.  VERR_INTERRUPTED and VERR_TIMEOUT are considered
    777  *          harmless, while all other error status are fatal.
    778  * @param   aMillies    Number of milliseconds to wait.
    779  */
    780 int USBProxyService::wait(RTMSINTERVAL aMillies)
    781 {
    782     return RTThreadSleep(RT_MIN(aMillies, 250));
    783 }
    784 
    785 
    786 /**
    787  * Interrupt any wait() call in progress.
    788  *
    789  * The default implementation in USBProxyService just a dummy stub.
    790  *
    791  * @returns VBox status code.
    792  */
    793 int USBProxyService::interruptWait(void)
    794 {
    795     return VERR_NOT_IMPLEMENTED;
    796 }
    797448
    798449
     
    851502 * Process any relevant changes in the attached USB devices.
    852503 *
    853  * Except for the first call, this is always running on the service thread.
    854  */
    855 void USBProxyService::processChanges(void)
     504 * This is called from any available USB proxy backends service thread when they discover
     505 * a change.
     506 */
     507void USBProxyService::i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices)
    856508{
    857509    LogFlowThisFunc(("\n"));
    858510
    859     /*
    860      * Get the sorted list of USB devices.
    861      */
    862     PUSBDEVICE pDevices = getDevices();
    863511    pDevices = sortDevices(pDevices);
    864512
     
    897545                              COMMA_LOCKVAL_SRC_POS);
    898546
     547        /* Skip all devices not belonging to the same backend. */
     548        if (   !pHostDevice.isNull()
     549            && pHostDevice->i_getUsbProxyBackend() != pUsbProxyBackend)
     550        {
     551            ++it;
     552            continue;
     553        }
     554
    899555        /*
    900556         * Compare.
     
    924580            devLock.release();
    925581            alock.release();
    926             if (updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
    927                 deviceChanged(pHostDevice,
    928                               (fRunFilters ? &llOpenedMachines : NULL),
    929                               pIgnoreMachine);
     582            if (pUsbProxyBackend->updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
     583                pUsbProxyBackend->deviceChanged(pHostDevice,
     584                                                (fRunFilters ? &llOpenedMachines : NULL),
     585                                                pIgnoreMachine);
    930586            alock.acquire();
    931587            ++it;
     
    944600                ComObjPtr<HostUSBDevice> NewObj;
    945601                NewObj.createObject();
    946                 NewObj->init(pNew, this);
     602                NewObj->init(pNew, pUsbProxyBackend);
    947603                Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
    948604                     (HostUSBDevice *)NewObj,
     
    959615                devLock.release();
    960616                alock.release();
    961                 deviceAdded(NewObj, llOpenedMachines, pNew);
     617                pUsbProxyBackend->deviceAdded(NewObj, llOpenedMachines, pNew);
    962618                alock.acquire();
    963619            }
     
    975631                    devLock.release();
    976632                    alock.release();
    977                     deviceRemoved(pHostDevice);
     633                    pUsbProxyBackend->deviceRemoved(pHostDevice);
    978634                    Log(("USBProxyService::processChanges: detached %p {%s}\n",
    979635                         (HostUSBDevice *)pHostDevice,
     
    995651
    996652/**
    997  * Get a list of USB device currently attached to the host.
    998  *
    999  * The default implementation in USBProxyService just a dummy stub.
    1000  *
    1001  * @returns Pointer to a list of USB devices.
    1002  *          The list nodes are freed individually by calling freeDevice().
    1003  */
    1004 PUSBDEVICE USBProxyService::getDevices(void)
    1005 {
    1006     return NULL;
    1007 }
    1008 
    1009 
    1010 /**
    1011  * Performs the required actions when a device has been added.
    1012  *
    1013  * This means things like running filters and subsequent capturing and
    1014  * VM attaching. This may result in IPC and temporary lock abandonment.
    1015  *
    1016  * @param   aDevice     The device in question.
    1017  * @param   aUSBDevice  The USB device structure.
    1018  */
    1019 void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
    1020                                   SessionMachinesList &llOpenedMachines,
    1021                                   PUSBDEVICE aUSBDevice)
    1022 {
    1023     /*
    1024      * Validate preconditions.
    1025      */
    1026     AssertReturnVoid(!isWriteLockOnCurrentThread());
    1027     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    1028     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    1029     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
    1030                      (HostUSBDevice *)aDevice,
    1031                      aDevice->i_getName().c_str(),
    1032                      aDevice->i_getStateName(),
    1033                      aDevice->i_getId().raw()));
    1034 
    1035     /*
    1036      * Run filters on the device.
    1037      */
    1038     if (aDevice->i_isCapturableOrHeld())
    1039     {
    1040         devLock.release();
    1041         HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
    1042         AssertComRC(rc);
    1043     }
    1044 
    1045     NOREF(aUSBDevice);
    1046 }
    1047 
    1048 
    1049 /**
    1050  * Remove device notification hook for the OS specific code.
    1051  *
    1052  * This is means things like
    1053  *
    1054  * @param   aDevice     The device in question.
    1055  */
    1056 void USBProxyService::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
    1057 {
    1058     /*
    1059      * Validate preconditions.
    1060      */
    1061     AssertReturnVoid(!isWriteLockOnCurrentThread());
    1062     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    1063     AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    1064     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
    1065                      (HostUSBDevice *)aDevice,
    1066                      aDevice->i_getName().c_str(),
    1067                      aDevice->i_getStateName(),
    1068                      aDevice->i_getId().raw()));
    1069 
    1070     /*
    1071      * Detach the device from any machine currently using it,
    1072      * reset all data and uninitialize the device object.
    1073      */
    1074     devLock.release();
    1075     aDevice->i_onPhysicalDetached();
    1076 }
    1077 
    1078 
    1079 /**
    1080  * Implement fake capture, ++.
    1081  *
    1082  * @returns true if there is a state change.
    1083  * @param   pDevice     The device in question.
    1084  * @param   pUSBDevice  The USB device structure for the last enumeration.
    1085  * @param   aRunFilters Whether or not to run filters.
    1086  */
    1087 bool USBProxyService::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    1088                                             SessionMachine **aIgnoreMachine)
    1089 {
    1090     *aRunFilters = false;
    1091     *aIgnoreMachine = NULL;
    1092     AssertReturn(aDevice, false);
    1093     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    1094 
    1095     /*
    1096      * Just hand it to the device, it knows best what needs to be done.
    1097      */
    1098     return aDevice->i_updateStateFake(aUSBDevice, aRunFilters, aIgnoreMachine);
    1099 }
    1100 
    1101 
    1102 /**
    1103  * Updates the device state.
    1104  *
    1105  * This is responsible for calling HostUSBDevice::updateState().
    1106  *
    1107  * @returns true if there is a state change.
    1108  * @param   aDevice         The device in question.
    1109  * @param   aUSBDevice      The USB device structure for the last enumeration.
    1110  * @param   aRunFilters     Whether or not to run filters.
    1111  * @param   aIgnoreMachine  Machine to ignore when running filters.
    1112  */
    1113 bool USBProxyService::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    1114                                         SessionMachine **aIgnoreMachine)
    1115 {
    1116     AssertReturn(aDevice, false);
    1117     AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
    1118 
    1119     return aDevice->i_updateState(aUSBDevice, aRunFilters, aIgnoreMachine);
    1120 }
    1121 
    1122 
    1123 /**
    1124  * Handle a device which state changed in some significant way.
    1125  *
    1126  * This means things like running filters and subsequent capturing and
    1127  * VM attaching. This may result in IPC and temporary lock abandonment.
    1128  *
    1129  * @param   aDevice         The device.
    1130  * @param   pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters
    1131  * @param   aIgnoreMachine  Machine to ignore when running filters.
    1132  */
    1133 void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
    1134                                     SessionMachine *aIgnoreMachine)
    1135 {
    1136     /*
    1137      * Validate preconditions.
    1138      */
    1139     AssertReturnVoid(!isWriteLockOnCurrentThread());
    1140     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    1141     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    1142     LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
    1143                      (HostUSBDevice *)aDevice,
    1144                      aDevice->i_getName().c_str(),
    1145                      aDevice->i_getStateName(),
    1146                      aDevice->i_getId().raw(),
    1147                      (pllOpenedMachines != NULL),       // used to be "bool aRunFilters"
    1148                      aIgnoreMachine));
    1149     devLock.release();
    1150 
    1151     /*
    1152      * Run filters if requested to do so.
    1153      */
    1154     if (pllOpenedMachines)
    1155     {
    1156         HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine);
    1157         AssertComRC(rc);
    1158     }
    1159 }
    1160 
    1161 
    1162 
    1163 /**
    1164  * Free all the members of a USB device returned by getDevice().
    1165  *
    1166  * @param   pDevice     Pointer to the device.
    1167  */
    1168 /*static*/ void
    1169 USBProxyService::freeDeviceMembers(PUSBDEVICE pDevice)
    1170 {
    1171     RTStrFree((char *)pDevice->pszManufacturer);
    1172     pDevice->pszManufacturer = NULL;
    1173     RTStrFree((char *)pDevice->pszProduct);
    1174     pDevice->pszProduct = NULL;
    1175     RTStrFree((char *)pDevice->pszSerialNumber);
    1176     pDevice->pszSerialNumber = NULL;
    1177 
    1178     RTStrFree((char *)pDevice->pszAddress);
    1179     pDevice->pszAddress = NULL;
    1180 #ifdef RT_OS_WINDOWS
    1181     RTStrFree(pDevice->pszAltAddress);
    1182     pDevice->pszAltAddress = NULL;
    1183     RTStrFree(pDevice->pszHubName);
    1184     pDevice->pszHubName = NULL;
    1185 #elif defined(RT_OS_SOLARIS)
    1186     RTStrFree(pDevice->pszDevicePath);
    1187     pDevice->pszDevicePath = NULL;
    1188 #endif
    1189 }
    1190 
    1191 
    1192 /**
    1193  * Free one USB device returned by getDevice().
    1194  *
    1195  * @param   pDevice     Pointer to the device.
    1196  */
    1197 /*static*/ void
    1198 USBProxyService::freeDevice(PUSBDEVICE pDevice)
    1199 {
    1200     freeDeviceMembers(pDevice);
    1201     RTMemFree(pDevice);
    1202 }
    1203 
    1204 
    1205 /**
    1206  * Initializes a filter with the data from the specified device.
    1207  *
    1208  * @param   aFilter     The filter to fill.
    1209  * @param   aDevice     The device to fill it with.
    1210  */
    1211 /*static*/ void
    1212 USBProxyService::initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice)
    1213 {
    1214     PCUSBDEVICE pDev = aDevice->mUsb;
    1215     int vrc;
    1216 
    1217     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_VENDOR_ID,         pDev->idVendor,         true); AssertRC(vrc);
    1218     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_PRODUCT_ID,        pDev->idProduct,        true); AssertRC(vrc);
    1219     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_REV,        pDev->bcdDevice,        true); AssertRC(vrc);
    1220     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_CLASS,      pDev->bDeviceClass,     true); AssertRC(vrc);
    1221     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_SUB_CLASS,  pDev->bDeviceSubClass,  true); AssertRC(vrc);
    1222     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_PROTOCOL,   pDev->bDeviceProtocol,  true); AssertRC(vrc);
    1223     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_PORT,              pDev->bPort,            false); AssertRC(vrc);
    1224     vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_BUS,               pDev->bBus,             false); AssertRC(vrc);
    1225     if (pDev->pszSerialNumber)
    1226     {
    1227         vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber, true);
    1228         AssertRC(vrc);
    1229     }
    1230     if (pDev->pszProduct)
    1231     {
    1232         vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_PRODUCT_STR, pDev->pszProduct, true);
    1233         AssertRC(vrc);
    1234     }
    1235     if (pDev->pszManufacturer)
    1236     {
    1237         vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer, true);
    1238         AssertRC(vrc);
    1239     }
     653 * Returns the global USB filter list stored in the Host object.
     654 *
     655 * @returns nothing.
     656 * @param   pGlobalFilters    Where to store the global filter list on success.
     657 */
     658void USBProxyService::i_getUSBFilters(USBDeviceFilterList *pGlobalFilters)
     659{
     660    mHost->i_getUSBFilters(pGlobalFilters);
    1240661}
    1241662
  • trunk/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp

    r59116 r59117  
    4949 * Initializes the object (called right after construction).
    5050 *
    51  * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    52  */
    53 HRESULT USBProxyServiceDarwin::init(void)
     51 * @returns VBox status code.
     52 */
     53int USBProxyServiceDarwin::init(void)
    5454{
    5555    /*
     
    5858    int rc = USBLibInit();
    5959    if (RT_FAILURE(rc))
    60     {
    61         mLastError = rc;
    62         return S_OK;
    63     }
     60        return rc;
     61
    6462    mUSBLibInitialized = true;
    6563
     
    6866     */
    6967    start();
    70     return S_OK;
     68    return VINF_SUCCESS;
    7169}
    7270
     
    135133    int rc = DarwinReEnumerateUSBDevice(aDevice->mUsb);
    136134    if (RT_SUCCESS(rc))
    137         aDevice->mOneShotId = pvId;
     135        aDevice->i_setBackendUserData(pvId);
    138136    else
    139137    {
     
    153151     * Remove the one-shot filter if necessary.
    154152     */
    155     LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->mOneShotId));
    156     if (!aSuccess && aDevice->mOneShotId)
    157         USBLibRemoveFilter(aDevice->mOneShotId);
    158     aDevice->mOneShotId = NULL;
     153    LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
     154    if (!aSuccess && aDevice->i_getBackendUserData())
     155        USBLibRemoveFilter(aDevice->i_getBackendUserData());
     156    aDevice->i_setBackendUserData(NULL);
    159157}
    160158
     
    189187    int rc = DarwinReEnumerateUSBDevice(aDevice->mUsb);
    190188    if (RT_SUCCESS(rc))
    191         aDevice->mOneShotId = pvId;
     189        aDevice->i_setBackendUserData(pvId);
    192190    else
    193191    {
     
    207205     * Remove the one-shot filter if necessary.
    208206     */
    209     LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->mOneShotId));
    210     if (!aSuccess && aDevice->mOneShotId)
    211         USBLibRemoveFilter(aDevice->mOneShotId);
    212     aDevice->mOneShotId = NULL;
     207    LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
     208    if (!aSuccess && aDevice->i_getBackendUserData())
     209        USBLibRemoveFilter(aDevice->i_getBackendUserData());
     210    aDevice->i_setBackendUserData(NULL);
    213211}
    214212
  • trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp

    r59116 r59117  
    7272 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    7373 */
    74 HRESULT USBProxyServiceFreeBSD::init(void)
     74int USBProxyServiceFreeBSD::init(void)
    7575{
    7676    /*
     
    7979    int rc = RTSemEventCreate(&mNotifyEventSem);
    8080    if (RT_FAILURE(rc))
    81     {
    82         mLastError = rc;
    83         return E_FAIL;
    84     }
     81        return rc;
    8582
    8683    /*
     
    8885     */
    8986    start();
    90     return S_OK;
     87    return VINF_SUCCESS;
    9188}
    9289
  • trunk/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp

    r59043 r59117  
    11/* $Id$ */
    22/** @file
    3  * VirtualBox USB Proxy Service, Linux Specialization.
     3 * VirtualBox USB Proxy Backend, USB/IP.
    44 */
    55
    66/*
    7  * Copyright (C) 2005-2012 Oracle Corporation
     7 * Copyright (C) 2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3232#include <iprt/assert.h>
    3333#include <iprt/ctype.h>
    34 #include <iprt/dir.h>
     34#include <iprt/tcp.h>
    3535#include <iprt/env.h>
    36 #include <iprt/file.h>
    3736#include <iprt/err.h>
    3837#include <iprt/mem.h>
    39 #include <iprt/param.h>
    40 #include <iprt/path.h>
    4138#include <iprt/pipe.h>
    42 #include <iprt/stream.h>
    43 #include <iprt/linux/sysfs.h>
    44 
    45 #include <stdlib.h>
    46 #include <string.h>
    47 #include <stdio.h>
    48 #include <errno.h>
    49 #include <fcntl.h>
    50 #include <unistd.h>
    51 #include <sys/statfs.h>
    52 #include <sys/poll.h>
    53 #ifdef VBOX_WITH_LINUX_COMPILER_H
    54 # include <linux/compiler.h>
    55 #endif
    56 #include <linux/usbdevice_fs.h>
    57 
     39#include <iprt/asm.h>
     40#include <iprt/cdefs.h>
     41
     42/** The USB/IP default port to connect to. */
     43#define USBIP_PORT_DEFAULT    3240
     44/** The USB version number used for the protocol. */
     45#define USBIP_VERSION         UINT16_C(0x0111)
     46/** Request indicator in the command code. */
     47#define USBIP_INDICATOR_REQ   RT_BIT(15)
     48
     49/** Command/Reply code for OP_REQ/RET_DEVLIST. */
     50#define USBIP_REQ_RET_DEVLIST UINT16_C(5)
     51
     52/** @todo: Duplicate code in USBProxyDevice-usbip.cpp */
     53/**
     54 * Exported device entry in the OP_RET_DEVLIST reply.
     55 */
     56#pragma pack(1)
     57typedef struct UsbIpExportedDevice
     58{
     59    /** Path of the device, zero terminated string. */
     60    char     szPath[256];
     61    /** Bus ID of the exported device, zero terminated string. */
     62    char     szBusId[32];
     63    /** Bus number. */
     64    uint32_t u32BusNum;
     65    /** Device number. */
     66    uint32_t u32DevNum;
     67    /** Speed indicator of the device. */
     68    uint32_t u32Speed;
     69    /** Vendor ID of the device. */
     70    uint16_t u16VendorId;
     71    /** Product ID of the device. */
     72    uint16_t u16ProductId;
     73    /** Device release number. */
     74    uint16_t u16BcdDevice;
     75    /** Device class. */
     76    uint8_t  bDeviceClass;
     77    /** Device Subclass. */
     78    uint8_t  bDeviceSubClass;
     79    /** Device protocol. */
     80    uint8_t  bDeviceProtocol;
     81    /** Configuration value. */
     82    uint8_t  bConfigurationValue;
     83    /** Current configuration value of the device. */
     84    uint8_t  bNumConfigurations;
     85    /** Number of interfaces for the device. */
     86    uint8_t  bNumInterfaces;
     87} UsbIpExportedDevice;
     88/** Pointer to a exported device entry. */
     89typedef UsbIpExportedDevice *PUsbIpExportedDevice;
     90#pragma pack()
     91AssertCompileSize(UsbIpExportedDevice, 312);
     92
     93/**
     94 * Interface descriptor entry for an exported device.
     95 */
     96#pragma pack(1)
     97typedef struct UsbIpDeviceInterface
     98{
     99    /** Intefrace class. */
     100    uint8_t  bInterfaceClass;
     101    /** Interface sub class. */
     102    uint8_t  bInterfaceSubClass;
     103    /** Interface protocol identifier. */
     104    uint8_t  bInterfaceProtocol;
     105    /** Padding byte for alignment. */
     106    uint8_t  bPadding;
     107} UsbIpDeviceInterface;
     108/** Pointer to an interface descriptor entry. */
     109typedef UsbIpDeviceInterface *PUsbIpDeviceInterface;
     110#pragma pack()
     111
     112/**
     113 * USB/IP device list request.
     114 */
     115#pragma pack(1)
     116typedef struct UsbIpReqDevList
     117{
     118    /** Protocol version number. */
     119    uint16_t     u16Version;
     120    /** Command code. */
     121    uint16_t     u16Cmd;
     122    /** Status field, unused. */
     123    int32_t      u32Status;
     124} UsbIpReqDevList;
     125/** Pointer to a device list request. */
     126typedef UsbIpReqDevList *PUsbIpReqDevList;
     127#pragma pack()
     128
     129/**
     130 * USB/IP Import reply.
     131 *
     132 * This is only the header, for successful
     133 * requests the device details are sent to as
     134 * defined in UsbIpExportedDevice.
     135 */
     136#pragma pack(1)
     137typedef struct UsbIpRetDevList
     138{
     139    /** Protocol version number. */
     140    uint16_t     u16Version;
     141    /** Command code. */
     142    uint16_t     u16Cmd;
     143    /** Status field, unused. */
     144    int32_t      u32Status;
     145    /** Number of exported devices. */
     146    uint32_t     u32DevicesExported;
     147} UsbIpRetDevList;
     148/** Pointer to a import reply. */
     149typedef UsbIpRetDevList *PUsbIpRetDevList;
     150#pragma pack()
     151
     152/** Pollset id of the socket. */
     153#define USBIP_POLL_ID_SOCKET 0
     154/** Pollset id of the pipe. */
     155#define USBIP_POLL_ID_PIPE   1
     156
     157/** @name USB/IP error codes.
     158 * @{ */
     159/** Success indicator. */
     160#define USBIP_STATUS_SUCCESS                 INT32_C(0)
     161/** @} */
     162
     163/** @name USB/IP device speeds.
     164 * @{ */
     165/** Unknown speed. */
     166#define USBIP_SPEED_UNKNOWN  0
     167/** Low (1.0) speed. */
     168#define USBIP_SPEED_LOW      1
     169/** Full (1.1) speed. */
     170#define USBIP_SPEED_FULL     2
     171/** High (2.0) speed. */
     172#define USBIP_SPEED_HIGH     3
     173/** Variable (CWUSB) speed. */
     174#define USBIP_SPEED_WIRELESS 4
     175/** Super (3.0) speed. */
     176#define USBIP_SPEED_SUPER    5
     177/** @} */
     178
     179/**
     180 * Private USB/IP proxy backend data.
     181 */
     182struct USBProxyBackendUsbIp::Data
     183{
     184    Data()
     185        : hSocket(NIL_RTSOCKET),
     186          hWakeupPipeR(NIL_RTPIPE),
     187          hWakeupPipeW(NIL_RTPIPE),
     188          hPollSet(NIL_RTPOLLSET),
     189          uPort(USBIP_PORT_DEFAULT),
     190          pszHost(NULL),
     191          hMtxDevices(NIL_RTSEMFASTMUTEX),
     192          cUsbDevicesCur(0),
     193          pUsbDevicesCur(NULL),
     194          enmRecvState(kUsbIpRecvState_Invalid),
     195          cbResidualRecv(0),
     196          pbRecvBuf(NULL),
     197          cDevicesLeft(0),
     198          pHead(NULL),
     199          ppNext(&pHead)
     200    { }
     201
     202    /** Socket handle to the server. */
     203    RTSOCKET       hSocket;
     204    /** Pipe used to interrupt wait(), the read end. */
     205    RTPIPE         hWakeupPipeR;
     206    /** Pipe used to interrupt wait(), the write end. */
     207    RTPIPE         hWakeupPipeW;
     208    /** Pollset for the socket and wakeup pipe. */
     209    RTPOLLSET      hPollSet;
     210    /** Port of the USB/IP host to connect to. */
     211    uint32_t       uPort;
     212    /** USB/IP host address. */
     213    char          *pszHost;
     214    /** Mutex protecting the device list against concurrent access. */
     215    RTSEMFASTMUTEX hMtxDevices;
     216    /** Number of devices in the list. */
     217    uint32_t       cUsbDevicesCur;
     218    /** The current list of devices to compare with. */
     219    PUSBDEVICE     pUsbDevicesCur;
     220    /** Current receive state. */
     221    USBIPRECVSTATE enmRecvState;
     222    /** Scratch space for holding the data until it was completely received.
     223     * Which one to access is based on the current receive state. */
     224    union
     225    {
     226        UsbIpRetDevList      RetDevList;
     227        UsbIpExportedDevice  ExportedDevice;
     228        UsbIpDeviceInterface DeviceInterface;
     229        /** Byte view. */
     230        uint8_t              abRecv[1];
     231    } Scratch;
     232    /** Residual number of bytes to receive before we can work with the data. */
     233    size_t                   cbResidualRecv;
     234    /** Current pointer into the scratch buffer. */
     235    uint8_t                 *pbRecvBuf;
     236    /** Number of devices left to receive for the current request. */
     237    uint32_t                 cDevicesLeft;
     238    /** Number of interfaces to skip during receive. */
     239    uint32_t                 cInterfacesLeft;
     240    /** The current head pointer for the new device list. */
     241    PUSBDEVICE               pHead;
     242    /** The next pointer to add a device to. */
     243    PUSBDEVICE              *ppNext;
     244    /** Current amount of devices in the list. */
     245    uint32_t                 cDevicesCur;
     246};
     247
     248/**
     249 * Convert the given exported device structure from host to network byte order.
     250 *
     251 * @returns nothing.
     252 * @param   pDevice           The device structure to convert.
     253 */
     254DECLINLINE(void) usbProxyBackendUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
     255{
     256    pDevice->u32BusNum    = RT_N2H_U32(pDevice->u32BusNum);
     257    pDevice->u32DevNum    = RT_N2H_U32(pDevice->u32DevNum);
     258    pDevice->u32Speed     = RT_N2H_U16(pDevice->u32Speed);
     259    pDevice->u16VendorId  = RT_N2H_U16(pDevice->u16VendorId);
     260    pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
     261    pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
     262}
    58263
    59264/**
    60265 * Initialize data members.
    61266 */
    62 USBProxyServiceLinux::USBProxyServiceLinux(Host *aHost)
    63     : USBProxyService(aHost), mhFile(NIL_RTFILE), mhWakeupPipeR(NIL_RTPIPE),
    64       mhWakeupPipeW(NIL_RTPIPE), mUsingUsbfsDevices(true /* see init */),
    65       mUdevPolls(0), mpWaiter(NULL)
    66 {
    67     LogFlowThisFunc(("aHost=%p\n", aHost));
     267USBProxyBackendUsbIp::USBProxyBackendUsbIp(USBProxyService *aUsbProxyService)
     268    : USBProxyBackend(aUsbProxyService)
     269{
     270    LogFlowThisFunc(("aUsbProxyService=%p\n", aUsbProxyService));
    68271}
    69272
     
    73276 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    74277 */
    75 HRESULT USBProxyServiceLinux::init(void)
    76 {
    77     const char *pcszDevicesRoot;
    78     int rc = USBProxyLinuxChooseMethod(&mUsingUsbfsDevices, &pcszDevicesRoot);
     278int USBProxyBackendUsbIp::init(void)
     279{
     280    int rc = VINF_SUCCESS;
     281
     282    m = new Data;
     283
     284    /** @todo: Pass in some config like host and port to connect to. */
     285
     286    /* Setup wakeup pipe and poll set first. */
     287    rc = RTSemFastMutexCreate(&m->hMtxDevices);
    79288    if (RT_SUCCESS(rc))
    80289    {
    81         mDevicesRoot = pcszDevicesRoot;
    82         rc = mUsingUsbfsDevices ? initUsbfs() : initSysfs();
    83         /* For the day when we have VBoxSVC release logging... */
    84         LogRel((RT_SUCCESS(rc) ? "Successfully initialised host USB using %s\n"
    85                                : "Failed to initialise host USB using %s\n",
    86                 mUsingUsbfsDevices ? "USBFS" : "sysfs"));
    87     }
    88     mLastError = rc;
    89     return S_OK;
    90 }
    91 
    92 /**
    93  * Initialization routine for the usbfs based operation.
    94  *
    95  * @returns iprt status code.
    96  */
    97 int USBProxyServiceLinux::initUsbfs(void)
    98 {
    99     Assert(mUsingUsbfsDevices);
    100 
    101     /*
    102      * Open the devices file.
    103      */
    104     int rc;
    105     char *pszDevices = RTPathJoinA(mDevicesRoot.c_str(), "devices");
    106     if (pszDevices)
    107     {
    108         rc = RTFileOpen(&mhFile, pszDevices, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     290        rc = RTPipeCreate(&m->hWakeupPipeR, &m->hWakeupPipeW, 0);
    109291        if (RT_SUCCESS(rc))
    110292        {
    111             rc = RTPipeCreate(&mhWakeupPipeR, &mhWakeupPipeW, 0 /*fFlags*/);
     293            rc = RTPollSetCreate(&m->hPollSet);
    112294            if (RT_SUCCESS(rc))
    113295            {
    114                 /*
    115                  * Start the poller thread.
    116                  */
    117                 rc = start();
     296                rc = RTPollSetAddPipe(m->hPollSet, m->hWakeupPipeR,
     297                                      RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
    118298                if (RT_SUCCESS(rc))
    119299                {
    120                     RTStrFree(pszDevices);
    121                     LogFlowThisFunc(("returns successfully\n"));
    122                     return VINF_SUCCESS;
     300                    /* Connect to the USB/IP host. */
     301                    rc = reconnect();
     302                    if (RT_SUCCESS(rc))
     303                        rc = start(); /* Start service thread. */
    123304                }
    124305
    125                 RTPipeClose(mhWakeupPipeR);
    126                 RTPipeClose(mhWakeupPipeW);
    127                 mhWakeupPipeW = mhWakeupPipeR = NIL_RTPIPE;
     306                if (RT_FAILURE(rc))
     307                {
     308                    RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_PIPE);
     309                    int rc2 = RTPollSetDestroy(m->hPollSet);
     310                    AssertRC(rc2);
     311                }
    128312            }
    129             else
    130                 Log(("USBProxyServiceLinux::USBProxyServiceLinux: RTFilePipe failed with rc=%Rrc\n", rc));
    131             RTFileClose(mhFile);
    132         }
    133 
    134         RTStrFree(pszDevices);
    135     }
    136     else
    137     {
    138         rc = VERR_NO_MEMORY;
    139         Log(("USBProxyServiceLinux::USBProxyServiceLinux: out of memory!\n"));
    140     }
    141 
    142     LogFlowThisFunc(("returns failure!!! (rc=%Rrc)\n", rc));
     313
     314            if (RT_FAILURE(rc))
     315            {
     316                int rc2 = RTPipeClose(m->hWakeupPipeR);
     317                AssertRC(rc2);
     318                rc2 = RTPipeClose(m->hWakeupPipeW);
     319                AssertRC(rc2);
     320            }
     321        }
     322        if (RT_FAILURE(rc))
     323            RTSemFastMutexDestroy(m->hMtxDevices);
     324    }
     325
    143326    return rc;
    144327}
    145328
    146 
    147 /**
    148  * Initialization routine for the sysfs based operation.
    149  *
    150  * @returns iprt status code
    151  */
    152 int USBProxyServiceLinux::initSysfs(void)
    153 {
    154     Assert(!mUsingUsbfsDevices);
    155 
    156 #ifdef VBOX_USB_WITH_SYSFS
    157     try
    158     {
    159         mpWaiter = new VBoxMainHotplugWaiter(mDevicesRoot.c_str());
    160     }
    161     catch(std::bad_alloc &e)
    162     {
    163         return VERR_NO_MEMORY;
    164     }
    165     int rc = mpWaiter->getStatus();
    166     if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT || rc == VERR_TRY_AGAIN)
    167         rc = start();
    168     else if (rc == VERR_NOT_SUPPORTED)
    169         /* This can legitimately happen if hal or DBus are not running, but of
    170          * course we can't start in this case. */
    171         rc = VINF_SUCCESS;
    172     return rc;
    173 
    174 #else  /* !VBOX_USB_WITH_SYSFS */
    175     return VERR_NOT_IMPLEMENTED;
    176 #endif /* !VBOX_USB_WITH_SYSFS */
    177 }
    178 
    179 
    180329/**
    181330 * Stop all service threads and free the device chain.
    182331 */
    183 USBProxyServiceLinux::~USBProxyServiceLinux()
     332USBProxyBackendUsbIp::~USBProxyBackendUsbIp()
    184333{
    185334    LogFlowThisFunc(("\n"));
     
    194343     * Free resources.
    195344     */
    196     doUsbfsCleanupAsNeeded();
    197 #ifdef VBOX_USB_WITH_SYSFS
    198     if (mpWaiter)
    199         delete mpWaiter;
    200 #endif
    201 }
    202 
    203 
    204 /**
    205  * If any Usbfs-related resources are currently allocated, then free them
    206  * and mark them as freed.
    207  */
    208 void USBProxyServiceLinux::doUsbfsCleanupAsNeeded()
    209 {
    210     /*
    211      * Free resources.
    212      */
    213     RTFileClose(mhFile);
    214     mhFile = NIL_RTFILE;
    215 
    216     RTPipeClose(mhWakeupPipeR);
    217     RTPipeClose(mhWakeupPipeW);
    218     mhWakeupPipeW = mhWakeupPipeR = NIL_RTPIPE;
    219 }
    220 
    221 
    222 int USBProxyServiceLinux::captureDevice(HostUSBDevice *aDevice)
     345    if (m->hPollSet != NIL_RTPOLLSET)
     346    {
     347        disconnect();
     348
     349        int rc = RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_PIPE);
     350        AssertRC(rc);
     351        rc = RTPollSetDestroy(m->hPollSet);
     352        AssertRC(rc);
     353        rc = RTPipeClose(m->hWakeupPipeR);
     354        AssertRC(rc);
     355        rc = RTPipeClose(m->hWakeupPipeW);
     356        AssertRC(rc);
     357    }
     358
     359    if (m->pszHost)
     360        RTStrFree(m->pszHost);
     361    if (m->hMtxDevices != NIL_RTSEMFASTMUTEX)
     362        RTSemFastMutexDestroy(m->hMtxDevices);
     363
     364    delete m;
     365}
     366
     367
     368int USBProxyBackendUsbIp::captureDevice(HostUSBDevice *aDevice)
    223369{
    224370    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
     
    229375
    230376    /*
    231      * Don't think we need to do anything when the device is held... fake it.
     377     * We don't need to do anything when the device is held... fake it.
    232378     */
    233379    Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing);
     
    239385
    240386
    241 int USBProxyServiceLinux::releaseDevice(HostUSBDevice *aDevice)
     387int USBProxyBackendUsbIp::releaseDevice(HostUSBDevice *aDevice)
    242388{
    243389    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
     
    258404
    259405
    260 bool USBProxyServiceLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
     406bool USBProxyBackendUsbIp::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    261407                                             SessionMachine **aIgnoreMachine)
    262408{
     
    265411    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    266412    if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
    267         &&  aDevice->mUsb->enmState == USBDEVICESTATE_USED_BY_HOST)
     413        &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
    268414        LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
    269415                aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
     
    273419
    274420
    275 /**
    276  * A device was added, we need to adjust mUdevPolls.
    277  *
    278  * See USBProxyService::deviceAdded for details.
    279  */
    280 void USBProxyServiceLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
    281                                        PUSBDEVICE aUSBDevice)
    282 {
    283     AssertReturnVoid(aDevice);
    284     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    285     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    286     if (aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST)
    287     {
    288         LogRel(("USBProxy: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
    289                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
    290         mUdevPolls = 10; /* (10 * 500ms = 5s) */
    291     }
    292 
    293     devLock.release();
    294     USBProxyService::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
    295 }
    296 
    297 
    298 int USBProxyServiceLinux::wait(RTMSINTERVAL aMillies)
    299 {
    300     int rc;
    301     if (mUsingUsbfsDevices)
    302         rc = waitUsbfs(aMillies);
    303     else
    304         rc = waitSysfs(aMillies);
     421int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
     422{
     423    int rc = VINF_SUCCESS;
     424    bool fDeviceListChangedOrWokenUp = false;
     425
     426    /* Try to reconnect once when we enter if we lost the connection earlier. */
     427    if (m->hSocket == NIL_RTSOCKET)
     428        rc = reconnect();
     429
     430    /* Query a new device list upon entering. */
     431    if (m->enmRecvState == kUsbIpRecvState_None)
     432    {
     433        rc = startListExportedDevicesReq();
     434        if (RT_FAILURE(rc))
     435            disconnect();
     436    }
     437
     438    /*
     439     * Because the USB/IP protocol doesn't specify a way to get notified about
     440     * new or removed exported devices we have to poll the host periodically for
     441     * a new device list and compare it with the previous one notifying the proxy
     442     * service about changes.
     443     */
     444    while (   !fDeviceListChangedOrWokenUp
     445           && (aMillies == RT_INDEFINITE_WAIT || aMillies > 0)
     446           && RT_SUCCESS(rc))
     447    {
     448        RTMSINTERVAL msWait = aMillies;
     449        uint64_t msPollStart = RTTimeMilliTS();
     450        uint32_t uIdReady = 0;
     451        uint32_t fEventsRecv = 0;
     452
     453        /* Limit the waiting time to 1sec so we can either reconnect or get a new device list. */
     454        if (m->hSocket == NIL_RTSOCKET || m->enmRecvState == kUsbIpRecvState_None)
     455            msWait = RT_MIN(1000, aMillies);
     456
     457        rc = RTPoll(m->hPollSet, msWait, &fEventsRecv, &uIdReady);
     458        if (RT_SUCCESS(rc))
     459        {
     460            if (uIdReady == USBIP_POLL_ID_PIPE)
     461            {
     462                /* Drain the wakeup pipe. */
     463                char bRead = 0;
     464                size_t cbRead = 0;
     465
     466                rc = RTPipeRead(m->hWakeupPipeR, &bRead, 1, &cbRead);
     467                Assert(RT_SUCCESS(rc) && cbRead == 1);
     468                fDeviceListChangedOrWokenUp = true;
     469            }
     470            else if (uIdReady == USBIP_POLL_ID_SOCKET)
     471            {
     472                if (fEventsRecv & RTPOLL_EVT_ERROR)
     473                    rc = VERR_NET_SHUTDOWN;
     474                else
     475                    rc = receiveData();
     476                if (RT_SUCCESS(rc))
     477                {
     478                    /*
     479                     * If we are in the none state again we received the previous request
     480                     * and have a new device list to compare the old against.
     481                     */
     482                    if (m->enmRecvState == kUsbIpRecvState_None)
     483                    {
     484                        if (hasDevListChanged(m->pHead))
     485                            fDeviceListChangedOrWokenUp = true;
     486
     487                        /* Update to the new list in any case now that we have it anyway. */
     488                        RTSemFastMutexRequest(m->hMtxDevices);
     489                        freeDeviceList(m->pUsbDevicesCur);
     490                        m->cUsbDevicesCur = m->cDevicesCur;
     491                        m->pUsbDevicesCur = m->pHead;
     492                        RTSemFastMutexRelease(m->hMtxDevices);
     493
     494                        m->pHead = NULL;
     495                        resetRecvState();
     496                    }
     497                }
     498                else if (rc == VERR_NET_SHUTDOWN || rc == VERR_BROKEN_PIPE)
     499                {
     500                    LogRelMax(10, ("USB/IP: Lost connection to host \"%s\", trying to reconnect...\n", m->pszHost));
     501                    disconnect();
     502                    rc = VINF_SUCCESS;
     503                }
     504            }
     505            else
     506            {
     507                AssertMsgFailed(("Invalid poll ID returned\n"));
     508                rc = VERR_INVALID_STATE;
     509            }
     510            aMillies -= (RTTimeMilliTS() - msPollStart);
     511        }
     512        else if (rc == VERR_TIMEOUT)
     513        {
     514            aMillies -= msWait;
     515            if (aMillies)
     516            {
     517                /* Try to reconnect and start a new request if we lost the connection before. */
     518                if (m->hSocket == NIL_RTSOCKET)
     519                    rc = reconnect();
     520
     521                if (RT_SUCCESS(rc))
     522                    rc = startListExportedDevicesReq();
     523            }
     524        }
     525    }
     526
    305527    return rc;
    306528}
    307529
    308530
    309 /** String written to the wakeup pipe. */
    310 #define WAKE_UP_STRING      "WakeUp!"
    311 /** Length of the string written. */
    312 #define WAKE_UP_STRING_LEN  ( sizeof(WAKE_UP_STRING) - 1 )
    313 
    314 int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies)
    315 {
    316     struct pollfd PollFds[2];
    317 
    318     /* Cap the wait interval if we're polling for udevd changing device permissions. */
    319     if (aMillies > 500 && mUdevPolls > 0)
    320     {
    321         mUdevPolls--;
    322         aMillies = 500;
    323     }
    324 
    325     RT_ZERO(PollFds);
    326     PollFds[0].fd        = RTFileToNative(mhFile);
    327     PollFds[0].events    = POLLIN;
    328     PollFds[1].fd        = RTPipeToNative(mhWakeupPipeR);
    329     PollFds[1].events    = POLLIN | POLLERR | POLLHUP;
    330 
    331     int rc = poll(&PollFds[0], 2, aMillies);
    332     if (rc == 0)
    333         return VERR_TIMEOUT;
    334     if (rc > 0)
    335     {
    336         /* drain the pipe */
    337         if (PollFds[1].revents & POLLIN)
    338         {
    339             char szBuf[WAKE_UP_STRING_LEN];
    340             rc = RTPipeReadBlocking(mhWakeupPipeR, szBuf, sizeof(szBuf), NULL);
    341             AssertRC(rc);
    342         }
    343         return VINF_SUCCESS;
    344     }
    345     return RTErrConvertFromErrno(errno);
    346 }
    347 
    348 
    349 int USBProxyServiceLinux::waitSysfs(RTMSINTERVAL aMillies)
    350 {
    351 #ifdef VBOX_USB_WITH_SYSFS
    352     int rc = mpWaiter->Wait(aMillies);
    353     if (rc == VERR_TRY_AGAIN)
    354     {
    355         RTThreadYield();
    356         rc = VINF_SUCCESS;
    357     }
    358     return rc;
    359 #else  /* !VBOX_USB_WITH_SYSFS */
    360     return USBProxyService::wait(aMillies);
    361 #endif /* !VBOX_USB_WITH_SYSFS */
    362 }
    363 
    364 
    365 int USBProxyServiceLinux::interruptWait(void)
     531int USBProxyBackendUsbIp::interruptWait(void)
    366532{
    367533    AssertReturn(!isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
    368534
    369535    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    370 #ifdef VBOX_USB_WITH_SYSFS
    371     LogFlowFunc(("mUsingUsbfsDevices=%d\n", mUsingUsbfsDevices));
    372     if (!mUsingUsbfsDevices)
    373     {
    374         mpWaiter->Interrupt();
    375         LogFlowFunc(("Returning VINF_SUCCESS\n"));
    376         return VINF_SUCCESS;
    377     }
    378 #endif /* VBOX_USB_WITH_SYSFS */
    379     int rc = RTPipeWriteBlocking(mhWakeupPipeW, WAKE_UP_STRING, WAKE_UP_STRING_LEN, NULL);
     536
     537    int rc = RTPipeWriteBlocking(m->hWakeupPipeW, "", 1, NULL);
    380538    if (RT_SUCCESS(rc))
    381         RTPipeFlush(mhWakeupPipeW);
     539        RTPipeFlush(m->hWakeupPipeW);
    382540    LogFlowFunc(("returning %Rrc\n", rc));
    383541    return rc;
     
    385543
    386544
    387 PUSBDEVICE USBProxyServiceLinux::getDevices(void)
    388 {
    389     return USBProxyLinuxGetDevices(mDevicesRoot.c_str(), !mUsingUsbfsDevices);
    390 }
     545PUSBDEVICE USBProxyBackendUsbIp::getDevices(void)
     546{
     547    PUSBDEVICE pFirst = NULL;
     548    PUSBDEVICE *ppNext = &pFirst;
     549
     550    /* Create a deep copy of the device list. */
     551    RTSemFastMutexRequest(m->hMtxDevices);
     552    PUSBDEVICE pCur = m->pUsbDevicesCur;
     553    while (pCur)
     554    {
     555        PUSBDEVICE pNew = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE));
     556        if (pNew)
     557        {
     558            pNew->pszManufacturer    = RTStrDup(pCur->pszManufacturer);
     559            pNew->pszProduct         = RTStrDup(pCur->pszProduct);
     560            if (pCur->pszSerialNumber)
     561                pNew->pszSerialNumber = RTStrDup(pCur->pszSerialNumber);
     562            pNew->pszBackend         = RTStrDup(pCur->pszBackend);
     563            pNew->pszAddress         = RTStrDup(pCur->pszAddress);
     564
     565            pNew->idVendor           = pCur->idVendor;
     566            pNew->idProduct          = pCur->idProduct;
     567            pNew->bcdDevice          = pCur->bcdDevice;
     568            pNew->bcdUSB             = pCur->bcdUSB;
     569            pNew->bDeviceClass       = pCur->bDeviceClass;
     570            pNew->bDeviceSubClass    = pCur->bDeviceSubClass;
     571            pNew->bDeviceProtocol    = pCur->bDeviceProtocol;
     572            pNew->bNumConfigurations = pCur->bNumConfigurations;
     573            pNew->enmState           = pCur->enmState;
     574            pNew->u64SerialHash      = pCur->u64SerialHash;
     575            pNew->bBus               = pCur->bBus;
     576            pNew->bPort              = pCur->bPort;
     577            pNew->enmSpeed           = pCur->enmSpeed;
     578
     579            /* link it */
     580            pNew->pNext = NULL;
     581            pNew->pPrev = *ppNext;
     582            *ppNext = pNew;
     583            ppNext = &pNew->pNext;
     584        }
     585
     586        pCur = pCur->pNext;
     587    }
     588    RTSemFastMutexRelease(m->hMtxDevices);
     589
     590    return pFirst;
     591}
     592
     593/**
     594 * Frees a given device list.
     595 *
     596 * @returns nothing.
     597 * @param   pHead    The head of the device list to free.
     598 */
     599void USBProxyBackendUsbIp::freeDeviceList(PUSBDEVICE pHead)
     600{
     601    PUSBDEVICE pNext = pHead;
     602    while (pNext)
     603    {
     604        PUSBDEVICE pFree = pNext;
     605        pNext = pNext->pNext;
     606        freeDevice(pFree);
     607    }
     608}
     609
     610/**
     611 * Resets the receive state to the idle state.
     612 *
     613 * @returns nothing.
     614 */
     615void USBProxyBackendUsbIp::resetRecvState()
     616{
     617    freeDeviceList(m->pHead);
     618    m->pHead          = NULL;
     619    m->ppNext         = &m->pHead;
     620    m->cDevicesCur    = 0;
     621    m->enmRecvState   = kUsbIpRecvState_None;
     622    m->cbResidualRecv = 0;
     623    m->pbRecvBuf      = &m->Scratch.abRecv[0];
     624    m->cDevicesLeft   = 0;
     625}
     626
     627/**
     628 * Disconnects from the host and resets the receive state.
     629 *
     630 * @returns nothing.
     631 */
     632void USBProxyBackendUsbIp::disconnect()
     633{
     634    if (m->hSocket != NIL_RTSOCKET)
     635    {
     636        int rc = RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_SOCKET);
     637        Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
     638
     639        RTTcpClientCloseEx(m->hSocket, false /*fGracefulShutdown*/);
     640        m->hSocket = NIL_RTSOCKET;
     641    }
     642
     643    resetRecvState();
     644}
     645
     646/**
     647 * Tries to reconnect to the USB/IP host.
     648 *
     649 * @returns VBox status code.
     650 */
     651int USBProxyBackendUsbIp::reconnect()
     652{
     653    /* Make sure we are disconnected. */
     654    disconnect();
     655
     656    /* Connect to the USB/IP host. */
     657    int rc = RTTcpClientConnect(m->pszHost, m->uPort, &m->hSocket);
     658    if (RT_SUCCESS(rc))
     659    {
     660        rc = RTTcpSetSendCoalescing(m->hSocket, false);
     661        if (RT_FAILURE(rc))
     662            LogRel(("USB/IP: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect increased latency\n", rc));
     663
     664        rc = RTPollSetAddSocket(m->hPollSet, m->hSocket, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
     665                                USBIP_POLL_ID_SOCKET);
     666        if (RT_FAILURE(rc))
     667        {
     668            RTTcpClientCloseEx(m->hSocket, false /*fGracefulShutdown*/);
     669            m->hSocket = NIL_RTSOCKET;
     670        }
     671    }
     672
     673    return rc;
     674}
     675
     676/**
     677 * Initiates a new List Exported Devices request.
     678 *
     679 * @returns VBox status code.
     680 */
     681int USBProxyBackendUsbIp::startListExportedDevicesReq()
     682{
     683    int rc = VINF_SUCCESS;
     684
     685    /*
     686     * Reset the current state and reconnect in case we were called in the middle
     687     * of another transfer (which should not happen).
     688     */
     689    Assert(m->enmRecvState == kUsbIpRecvState_None);
     690    if (m->enmRecvState != kUsbIpRecvState_None)
     691        rc = reconnect();
     692
     693    if (RT_SUCCESS(rc))
     694    {
     695        /* Send of the request. */
     696        UsbIpReqDevList ReqDevList;
     697        ReqDevList.u16Version = RT_H2N_U16(USBIP_VERSION);
     698        ReqDevList.u16Cmd     = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_DEVLIST);
     699        ReqDevList.u32Status  = RT_H2N_U32(0);
     700        rc = RTTcpWrite(m->hSocket, &ReqDevList, sizeof(ReqDevList));
     701        if (RT_SUCCESS(rc))
     702            advanceState(kUsbIpRecvState_Hdr);
     703    }
     704
     705    return rc;
     706}
     707
     708/**
     709 * Advances the state machine to the given state.
     710 *
     711 * @returns nothing.
     712 * @param   enmRecvState    The new receive state.
     713 */
     714void USBProxyBackendUsbIp::advanceState(USBIPRECVSTATE enmRecvState)
     715{
     716    switch (enmRecvState)
     717    {
     718        case kUsbIpRecvState_None:
     719            break;
     720        case kUsbIpRecvState_Hdr:
     721        {
     722            m->cbResidualRecv = sizeof(UsbIpRetDevList);
     723            m->pbRecvBuf      = (uint8_t *)&m->Scratch.RetDevList;
     724            break;
     725        }
     726        case kUsbIpRecvState_ExportedDevice:
     727        {
     728            m->cbResidualRecv = sizeof(UsbIpExportedDevice);
     729            m->pbRecvBuf      = (uint8_t *)&m->Scratch.ExportedDevice;
     730            break;
     731        }
     732        case kUsbIpRecvState_DeviceInterface:
     733        {
     734            m->cbResidualRecv = sizeof(UsbIpDeviceInterface);
     735            m->pbRecvBuf      = (uint8_t *)&m->Scratch.DeviceInterface;
     736            break;
     737        }
     738        default:
     739            AssertMsgFailed(("Invalid USB/IP receive state %d\n", enmRecvState));
     740            return;
     741    }
     742
     743    m->enmRecvState = enmRecvState;
     744}
     745
     746/**
     747 * Receives data from the USB/IP host and processes it when everything for the current
     748 * state was received.
     749 *
     750 * @returns VBox status code.
     751 */
     752int USBProxyBackendUsbIp::receiveData()
     753{
     754    size_t cbRecvd = 0;
     755    int rc = RTTcpReadNB(m->hSocket, m->pbRecvBuf, m->cbResidualRecv, &cbRecvd);
     756    if (RT_SUCCESS(rc))
     757    {
     758        m->cbResidualRecv -= cbRecvd;
     759        m->pbRecvBuf      += cbRecvd;
     760        /* In case we received everything for the current state process the data. */
     761        if (!m->cbResidualRecv)
     762            rc = processData();
     763    }
     764
     765    return rc;
     766}
     767
     768/**
     769 * Processes the data in the scratch buffer based on the current state.
     770 *
     771 * @returns VBox status code.
     772 */
     773int USBProxyBackendUsbIp::processData()
     774{
     775    int rc = VINF_SUCCESS;
     776
     777    switch (m->enmRecvState)
     778    {
     779        case kUsbIpRecvState_Hdr:
     780        {
     781            /* Check that the reply matches our expectations. */
     782            if (   RT_N2H_U16(m->Scratch.RetDevList.u16Version) == USBIP_VERSION
     783                && RT_N2H_U16(m->Scratch.RetDevList.u16Cmd) == USBIP_REQ_RET_DEVLIST
     784                && RT_N2H_U32(m->Scratch.RetDevList.u32Status) == USBIP_STATUS_SUCCESS)
     785            {
     786                /* Populate the number of exported devices in the list and go to the next state. */
     787                m->cDevicesLeft = RT_N2H_U32(m->Scratch.RetDevList.u32DevicesExported);
     788                if (m->cDevicesLeft)
     789                    advanceState(kUsbIpRecvState_ExportedDevice);
     790                else
     791                    advanceState(kUsbIpRecvState_None);
     792            }
     793            else
     794            {
     795                LogRelMax(10, ("USB/IP: Host sent an invalid reply to the list exported device request (Version: %#x Cmd: %#x Status: %#x)\n",
     796                               RT_N2H_U16(m->Scratch.RetDevList.u16Version), RT_N2H_U16(m->Scratch.RetDevList.u16Cmd),
     797                               RT_N2H_U32(m->Scratch.RetDevList.u32Status)));
     798                rc = VERR_INVALID_STATE;
     799            }
     800            break;
     801        }
     802        case kUsbIpRecvState_ExportedDevice:
     803        {
     804            /* Create a new device and add it to the list. */
     805            usbProxyBackendUsbIpExportedDeviceN2H(&m->Scratch.ExportedDevice);
     806            rc = addDeviceToList(&m->Scratch.ExportedDevice);
     807            if (RT_SUCCESS(rc))
     808            {
     809                m->cInterfacesLeft = m->Scratch.ExportedDevice.bNumInterfaces;
     810                if (m->cInterfacesLeft)
     811                    advanceState(kUsbIpRecvState_DeviceInterface);
     812                else
     813                {
     814                    m->cDevicesLeft--;
     815                    if (m->cDevicesLeft)
     816                        advanceState(kUsbIpRecvState_ExportedDevice);
     817                    else
     818                        advanceState(kUsbIpRecvState_None);
     819                }
     820            }
     821            break;
     822        }
     823        case kUsbIpRecvState_DeviceInterface:
     824        {
     825            /*
     826             * If all interfaces for the current device were received receive the next device
     827             * if there is another one left, if not we are done with the current request.
     828             */
     829            m->cInterfacesLeft--;
     830            if (m->cInterfacesLeft)
     831                advanceState(kUsbIpRecvState_DeviceInterface);
     832            else
     833            {
     834                m->cDevicesLeft--;
     835                if (m->cDevicesLeft)
     836                    advanceState(kUsbIpRecvState_ExportedDevice);
     837                else
     838                    advanceState(kUsbIpRecvState_None);
     839            }
     840            break;
     841        }
     842        case kUsbIpRecvState_None:
     843        default:
     844            AssertMsgFailed(("Invalid USB/IP receive state %d\n", m->enmRecvState));
     845            return VERR_INVALID_STATE;
     846    }
     847
     848    return rc;
     849}
     850
     851/**
     852 * Creates a new USB device and adds it to the list.
     853 *
     854 * @returns VBox status code.
     855 * @param   pDev    Pointer to the USB/IP exported device structure to take
     856 *                  the information for the new device from.
     857 */
     858int USBProxyBackendUsbIp::addDeviceToList(PUsbIpExportedDevice pDev)
     859{
     860    PUSBDEVICE pNew = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE));
     861    if (!pNew)
     862        return VERR_NO_MEMORY;
     863
     864    pNew->pszManufacturer = RTStrDup("");
     865    pNew->pszProduct      = RTStrDup("");
     866    pNew->pszSerialNumber = NULL;
     867    pNew->pszBackend      = RTStrDup("usbip");
     868
     869    /* Make sure the Bus id is 0 terminated. */
     870    pDev->szBusId[31] = '\0';
     871    RTStrAPrintf((char **)&pNew->pszAddress, "usbip://%s:%u:%s", m->pszHost, m->uPort, &pDev->szBusId[0]);
     872
     873    pNew->idVendor           = pDev->u16VendorId;
     874    pNew->idProduct          = pDev->u16ProductId;
     875    pNew->bcdDevice          = pDev->u16BcdDevice;
     876    pNew->bDeviceClass       = pDev->bDeviceClass;
     877    pNew->bDeviceSubClass    = pDev->bDeviceSubClass;
     878    pNew->bDeviceProtocol    = pDev->bDeviceProtocol;
     879    pNew->bNumConfigurations = pDev->bNumConfigurations;
     880    pNew->enmState           = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
     881    pNew->u64SerialHash      = 0;
     882    pNew->bBus               = (uint8_t)pDev->u32BusNum;
     883    pNew->bPort              = (uint8_t)pDev->u32DevNum;
     884
     885    switch (pDev->u32Speed)
     886    {
     887        case USBIP_SPEED_LOW:
     888            pNew->enmSpeed = USBDEVICESPEED_LOW;
     889            pNew->bcdUSB = 1 << 8;
     890            break;
     891        case USBIP_SPEED_FULL:
     892            pNew->enmSpeed = USBDEVICESPEED_FULL;
     893            pNew->bcdUSB = 1 << 8;
     894            break;
     895        case USBIP_SPEED_HIGH:
     896            pNew->enmSpeed = USBDEVICESPEED_HIGH;
     897            pNew->bcdUSB = 2 << 8;
     898            break;
     899        case USBIP_SPEED_WIRELESS:
     900            pNew->enmSpeed = USBDEVICESPEED_VARIABLE;
     901            pNew->bcdUSB = 1 << 8;
     902            break;
     903        case USBIP_SPEED_SUPER:
     904            pNew->enmSpeed = USBDEVICESPEED_SUPER;
     905            pNew->bcdUSB = 3 << 8;
     906            break;
     907        case USBIP_SPEED_UNKNOWN:
     908        default:
     909            pNew->bcdUSB = 1 << 8;
     910            pNew->enmSpeed = USBDEVICESPEED_UNKNOWN;
     911    }
     912
     913    /* link it */
     914    pNew->pNext = NULL;
     915    pNew->pPrev = *m->ppNext;
     916    *m->ppNext = pNew;
     917    m->ppNext = &pNew->pNext;
     918    m->cDevicesCur++;
     919
     920    return VINF_SUCCESS;
     921}
     922
     923/**
     924 * Compares the given device list with the current one and returns whether it has
     925 * changed.
     926 *
     927 * @returns flag whether the device list has changed compared to the current one.
     928 * @param   pDevices    The device list to compare the current one against.
     929 */
     930bool USBProxyBackendUsbIp::hasDevListChanged(PUSBDEVICE pDevices)
     931{
     932    /** @todo */
     933    return true;
     934}
     935
  • trunk/src/VBox/Main/src-server/linux/USBGetDevices.cpp

    r58170 r59117  
    13521352                 pInfo->mDevice);
    13531353    Dev->pszAddress = pszAddress;
     1354    Dev->pszBackend = RTStrDup("host");
    13541355
    13551356    /* Work out from the data collected whether we can support this device. */
  • trunk/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp

    r59116 r59117  
    6060 * Initialize data members.
    6161 */
    62 USBProxyServiceLinux::USBProxyServiceLinux(Host *aHost)
    63     : USBProxyService(aHost), mhFile(NIL_RTFILE), mhWakeupPipeR(NIL_RTPIPE),
     62USBProxyBackendLinux::USBProxyBackendLinux(USBProxyService *aUsbProxyService)
     63    : USBProxyBackend(aUsbProxyService), mhFile(NIL_RTFILE), mhWakeupPipeR(NIL_RTPIPE),
    6464      mhWakeupPipeW(NIL_RTPIPE), mUsingUsbfsDevices(true /* see init */),
    6565      mUdevPolls(0), mpWaiter(NULL)
    6666{
    67     LogFlowThisFunc(("aHost=%p\n", aHost));
     67    LogFlowThisFunc(("aUsbProxyService=%p\n", aUsbProxyService));
    6868}
    6969
     
    7171 * Initializes the object (called right after construction).
    7272 *
    73  * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    74  */
    75 HRESULT USBProxyServiceLinux::init(void)
     73 * @returns VBox status code.
     74 */
     75int USBProxyBackendLinux::init(void)
    7676{
    7777    const char *pcszDevicesRoot;
     
    8686                mUsingUsbfsDevices ? "USBFS" : "sysfs"));
    8787    }
    88     mLastError = rc;
    89     return S_OK;
     88
     89    return rc;
    9090}
    9191
     
    9595 * @returns iprt status code.
    9696 */
    97 int USBProxyServiceLinux::initUsbfs(void)
     97int USBProxyBackendLinux::initUsbfs(void)
    9898{
    9999    Assert(mUsingUsbfsDevices);
     
    128128            }
    129129            else
    130                 Log(("USBProxyServiceLinux::USBProxyServiceLinux: RTFilePipe failed with rc=%Rrc\n", rc));
     130                Log(("USBProxyBackendLinux::USBProxyBackendLinux: RTFilePipe failed with rc=%Rrc\n", rc));
    131131            RTFileClose(mhFile);
    132132        }
     
    137137    {
    138138        rc = VERR_NO_MEMORY;
    139         Log(("USBProxyServiceLinux::USBProxyServiceLinux: out of memory!\n"));
     139        Log(("USBProxyBackendLinux::USBProxyBackendLinux: out of memory!\n"));
    140140    }
    141141
     
    150150 * @returns iprt status code
    151151 */
    152 int USBProxyServiceLinux::initSysfs(void)
     152int USBProxyBackendLinux::initSysfs(void)
    153153{
    154154    Assert(!mUsingUsbfsDevices);
     
    181181 * Stop all service threads and free the device chain.
    182182 */
    183 USBProxyServiceLinux::~USBProxyServiceLinux()
     183USBProxyBackendLinux::~USBProxyBackendLinux()
    184184{
    185185    LogFlowThisFunc(("\n"));
     
    206206 * and mark them as freed.
    207207 */
    208 void USBProxyServiceLinux::doUsbfsCleanupAsNeeded()
     208void USBProxyBackendLinux::doUsbfsCleanupAsNeeded()
    209209{
    210210    /*
     
    220220
    221221
    222 int USBProxyServiceLinux::captureDevice(HostUSBDevice *aDevice)
     222int USBProxyBackendLinux::captureDevice(HostUSBDevice *aDevice)
    223223{
    224224    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
     
    239239
    240240
    241 int USBProxyServiceLinux::releaseDevice(HostUSBDevice *aDevice)
     241int USBProxyBackendLinux::releaseDevice(HostUSBDevice *aDevice)
    242242{
    243243    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
     
    258258
    259259
    260 bool USBProxyServiceLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
     260bool USBProxyBackendLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
    261261                                             SessionMachine **aIgnoreMachine)
    262262{
     
    265265    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    266266    if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
    267         &&  aDevice->mUsb->enmState == USBDEVICESTATE_USED_BY_HOST)
     267        &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
    268268        LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
    269269                aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
     
    278278 * See USBProxyService::deviceAdded for details.
    279279 */
    280 void USBProxyServiceLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
     280void USBProxyBackendLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
    281281                                       PUSBDEVICE aUSBDevice)
    282282{
     
    292292
    293293    devLock.release();
    294     USBProxyService::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
    295 }
    296 
    297 
    298 int USBProxyServiceLinux::wait(RTMSINTERVAL aMillies)
     294    USBProxyBackend::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
     295}
     296
     297
     298int USBProxyBackendLinux::wait(RTMSINTERVAL aMillies)
    299299{
    300300    int rc;
     
    312312#define WAKE_UP_STRING_LEN  ( sizeof(WAKE_UP_STRING) - 1 )
    313313
    314 int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies)
     314int USBProxyBackendLinux::waitUsbfs(RTMSINTERVAL aMillies)
    315315{
    316316    struct pollfd PollFds[2];
     
    347347
    348348
    349 int USBProxyServiceLinux::waitSysfs(RTMSINTERVAL aMillies)
     349int USBProxyBackendLinux::waitSysfs(RTMSINTERVAL aMillies)
    350350{
    351351#ifdef VBOX_USB_WITH_SYSFS
     
    363363
    364364
    365 int USBProxyServiceLinux::interruptWait(void)
     365int USBProxyBackendLinux::interruptWait(void)
    366366{
    367367    AssertReturn(!isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
     
    385385
    386386
    387 PUSBDEVICE USBProxyServiceLinux::getDevices(void)
     387PUSBDEVICE USBProxyBackendLinux::getDevices(void)
    388388{
    389389    return USBProxyLinuxGetDevices(mDevicesRoot.c_str(), !mUsingUsbfsDevices);
  • trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp

    r59116 r59117  
    6565 * Initializes the object (called right after construction).
    6666 *
    67  * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    68  */
    69 HRESULT USBProxyServiceSolaris::init(void)
     67 * @returns VBox status code.
     68 */
     69int USBProxyServiceSolaris::init(void)
    7070{
    7171    /*
     
    7474    int rc = RTSemEventCreate(&mNotifyEventSem);
    7575    if (RT_FAILURE(rc))
    76     {
    77         mLastError = rc;
    78         return E_FAIL;
    79     }
     76        return rc;
    8077
    8178    /*
     
    8582    if (RT_FAILURE(rc))
    8683    {
    87         mLastError = rc;
    88         return S_OK;
    89     }
     84        RTSemEventDestroy(&mNotifyEventSem);
     85        return rc;
     86    }
     87
    9088    mUSBLibInitialized = true;
    9189
     
    9492     */
    9593    start();
    96     return S_OK;
     94    return VINF_SUCCESS;
    9795}
    9896
     
    342340
    343341    Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing);
    344     AssertReturn(aDevice->mUsb, VERR_INVALID_POINTER);
     342    AssertReturn(aDevice->i_getUsbData(), VERR_INVALID_POINTER);
    345343
    346344    /*
     
    358356    }
    359357
    360     PUSBDEVICE pDev = aDevice->mUsb;
     358    PUSBDEVICE pDev = aDevice->i_getUsbData();
    361359    int rc = USBLibResetDevice(pDev->pszDevicePath, true);
    362360    if (RT_SUCCESS(rc))
    363         aDevice->mOneShotId = pvId;
     361        aDevice->i_setBackendUserData(pvId);
    364362    else
    365363    {
     
    378376     * Remove the one-shot filter if necessary.
    379377     */
    380     LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->mOneShotId));
    381     if (!aSuccess && aDevice->mOneShotId)
     378    LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
     379    if (!aSuccess && aDevice->i_getBackendUserData())
    382380        USBLibRemoveFilter(aDevice->mOneShotId);
    383     aDevice->mOneShotId = NULL;
     381    aDevice->i_setBackendUserData(NULL);
    384382}
    385383
     
    397395
    398396    Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost);
    399     AssertReturn(aDevice->mUsb, VERR_INVALID_POINTER);
     397    AssertReturn(aDevice->i_getUsbData(), VERR_INVALID_POINTER);
    400398
    401399    /*
     
    413411    }
    414412
    415     PUSBDEVICE pDev = aDevice->mUsb;
     413    PUSBDEVICE pDev = aDevice->i_getUsbData();
    416414    int rc = USBLibResetDevice(pDev->pszDevicePath, true /* Re-attach */);
    417415    if (RT_SUCCESS(rc))
    418         aDevice->mOneShotId = pvId;
     416        aDevice->i_setBackendUserData(pvId);
    419417    else
    420418    {
     
    433431     * Remove the one-shot filter if necessary.
    434432     */
    435     LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->mOneShotId));
    436     if (!aSuccess && aDevice->mOneShotId)
    437         USBLibRemoveFilter(aDevice->mOneShotId);
    438     aDevice->mOneShotId = NULL;
     433    LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
     434    if (!aSuccess && aDevice->i_getBackendUserData())
     435        USBLibRemoveFilter(aDevice->i_getBackendUser());
     436    aDevice->i_setBackendUserData(NULL);
    439437}
    440438
  • trunk/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp

    r59116 r59117  
    5050 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    5151 */
    52 HRESULT USBProxyServiceWindows::init(void)
     52int USBProxyServiceWindows::init(void)
    5353{
    5454    /*
     
    5656     */
    5757    mhEventInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
    58     AssertReturn(mhEventInterrupt != INVALID_HANDLE_VALUE, E_FAIL);
     58    AssertReturn(mhEventInterrupt != INVALID_HANDLE_VALUE, VERR_OUT_OF_RESOURCES);
    5959
    6060    /*
     
    7171        {
    7272            LogFlowThisFunc(("returns successfully\n"));
    73             return S_OK;
     73            return VINF_SUCCESS;
    7474        }
    7575
     
    8181
    8282    LogFlowThisFunc(("returns failure!!! (rc=%Rrc)\n", rc));
    83     mLastError = rc;
    84     return S_OK;
     83    return rc;
    8584}
    8685
  • trunk/src/VBox/Main/testcase/Makefile.kmk

    r56825 r59117  
    208208tstUSBProxyLinux_SOURCES   = \
    209209        tstUSBProxyLinux.cpp \
    210         ../src-server/linux/USBProxyServiceLinux.cpp \
     210        ../src-server/linux/USBProxyBackendLinux.cpp \
    211211        ../src-server/linux/USBGetDevices.cpp
    212212tstUSBProxyLinux_INCS      = \
  • trunk/src/VBox/Main/testcase/tstUSBProxyLinux.cpp

    r57358 r59117  
    11/* $Id$ */
    22/** @file
    3  * USBProxyServiceLinux test case.
     3 * USBProxyBackendLinux test case.
    44 */
    55
     
    2121*********************************************************************************************************************************/
    2222
    23 #include "USBProxyService.h"
     23#include "USBProxyBackend.h"
    2424#include "USBGetDevices.h"
    2525
     
    3232/*** BEGIN STUBS ***/
    3333
    34 USBProxyService::USBProxyService(Host*) {}
    35 USBProxyService::~USBProxyService() {}
    36 HRESULT USBProxyService::init() { return S_OK; }
    37 int USBProxyService::start() { return VINF_SUCCESS; }
    38 int USBProxyService::stop() { return VINF_SUCCESS; }
    39 RWLockHandle *USBProxyService::lockHandle() const { return NULL; }
    40 void *USBProxyService::insertFilter(USBFILTER const*) { return NULL; }
    41 void USBProxyService::removeFilter(void*) {}
    42 int USBProxyService::captureDevice(HostUSBDevice*) { return VINF_SUCCESS; }
    43 void USBProxyService::captureDeviceCompleted(HostUSBDevice*, bool) {}
    44 void USBProxyService::detachingDevice(HostUSBDevice*) {}
    45 int USBProxyService::releaseDevice(HostUSBDevice*) { return VINF_SUCCESS; }
    46 void USBProxyService::releaseDeviceCompleted(HostUSBDevice*, bool) {}
    47 void USBProxyService::serviceThreadInit() {}
    48 void USBProxyService::serviceThreadTerm() {}
    49 int USBProxyService::wait(unsigned int) { return VINF_SUCCESS; }
    50 int USBProxyService::interruptWait() { return VINF_SUCCESS; }
    51 PUSBDEVICE USBProxyService::getDevices() { return NULL; }
    52 void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice) {}
    53 void USBProxyService::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice) {}
    54 void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList*, SessionMachine*) {}
    55 bool USBProxyService::updateDeviceState(HostUSBDevice*, USBDEVICE*, bool*, SessionMachine**) { return true; }
    56 bool USBProxyService::updateDeviceStateFake(HostUSBDevice*, USBDEVICE*, bool*, SessionMachine**) { return true; }
    57 bool USBProxyService::isActive() { return true; }
     34USBProxyBackend::USBProxyBackend(USBProxyService*) {}
     35USBProxyBackend::~USBProxyBackend() {}
     36int USBProxyBackend::init() { return VINF_SUCCESS; }
     37int USBProxyBackend::start() { return VINF_SUCCESS; }
     38int USBProxyBackend::stop() { return VINF_SUCCESS; }
     39RWLockHandle *USBProxyBackend::lockHandle() const { return NULL; }
     40void *USBProxyBackend::insertFilter(USBFILTER const*) { return NULL; }
     41void USBProxyBackend::removeFilter(void*) {}
     42int USBProxyBackend::captureDevice(HostUSBDevice*) { return VINF_SUCCESS; }
     43void USBProxyBackend::captureDeviceCompleted(HostUSBDevice*, bool) {}
     44void USBProxyBackend::detachingDevice(HostUSBDevice*) {}
     45int USBProxyBackend::releaseDevice(HostUSBDevice*) { return VINF_SUCCESS; }
     46void USBProxyBackend::releaseDeviceCompleted(HostUSBDevice*, bool) {}
     47void USBProxyBackend::serviceThreadInit() {}
     48void USBProxyBackend::serviceThreadTerm() {}
     49int USBProxyBackend::wait(unsigned int) { return VINF_SUCCESS; }
     50int USBProxyBackend::interruptWait() { return VINF_SUCCESS; }
     51PUSBDEVICE USBProxyBackend::getDevices() { return NULL; }
     52void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice) {}
     53void USBProxyBackend::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice) {}
     54void USBProxyBackend::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList*, SessionMachine*) {}
     55bool USBProxyBackend::updateDeviceState(HostUSBDevice*, USBDEVICE*, bool*, SessionMachine**) { return true; }
     56bool USBProxyBackend::updateDeviceStateFake(HostUSBDevice*, USBDEVICE*, bool*, SessionMachine**) { return true; }
     57bool USBProxyBackend::isActive() { return true; }
    5858
    5959VBoxMainHotplugWaiter::VBoxMainHotplugWaiter(char const*) {}
     
    6262{
    6363    return Utf8Str();
    64 }
    65 
    66 int USBProxyService::getLastError(void)
    67 {
    68     return mLastError;
    6964}
    7065
  • trunk/src/VBox/VMM/VMMR3/PDMUsb.cpp

    r58126 r59117  
    983983 * @param   pUVM                The user mode VM handle.
    984984 * @param   pUuid               The UUID to be associated with the device.
    985  * @param   fRemote             Whether it's a remove or local device.
     985 * @param   pszBackend          The proxy backend to use.
    986986 * @param   pszAddress          The address string.
    987987 * @param   pvBackend           Pointer to the backend.
     
    990990 * @param   pszCaptureFilename  Path to the file for USB traffic capturing, optional.
    991991 */
    992 VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend,
     992VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, void *pvBackend,
    993993                                         uint32_t iUsbVersion, uint32_t fMaskedIfs, const char *pszCaptureFilename)
    994994{
     
    10401040        rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid));                    AssertRCBreak(rc);
    10411041        rc = CFGMR3InsertString(pConfig,  "UUID", szUuid);                      AssertRCBreak(rc);
    1042         rc = CFGMR3InsertInteger(pConfig, "Remote", fRemote);                   AssertRCBreak(rc);
     1042        rc = CFGMR3InsertString(pConfig, "Backend", pszBackend);                AssertRCBreak(rc);
    10431043        rc = CFGMR3InsertInteger(pConfig, "USBVersion", iUsbVersion);           AssertRCBreak(rc);
    10441044        rc = CFGMR3InsertInteger(pConfig, "pvBackend", (uintptr_t)pvBackend);   AssertRCBreak(rc);
Note: See TracChangeset for help on using the changeset viewer.

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