[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [PATCH 2/6] Add device list to track XenIface device(s)



> -----Original Message-----
> From: win-pv-devel [mailto:win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx] On
> Behalf Of Owen Smith
> Sent: 05 July 2016 11:38
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Owen Smith
> Subject: [win-pv-devel] [PATCH 2/6] Add device list to track XenIface
> device(s)
> 
> Uses RegisterDeviceNotificationA and SetupApi to track
> GUID_INTERFACE_XENIFACE device(s). Calls service base class
> after insertion and before remove complete.
> 
> Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>

Acked-by: Paul Durrant <paul.durrant@xxxxxxxxxx>

> ---
>  src/xenagent/devicelist.cpp      | 296
> +++++++++++++++++++++++++++++++++++++++
>  src/xenagent/devicelist.h        |  92 ++++++++++++
>  src/xenagent/service.cpp         |  20 ++-
>  src/xenagent/service.h           |  11 +-
>  vs2012/xenagent/xenagent.vcxproj |   2 +
>  vs2013/xenagent/xenagent.vcxproj |   2 +
>  6 files changed, 421 insertions(+), 2 deletions(-)
>  create mode 100644 src/xenagent/devicelist.cpp
>  create mode 100644 src/xenagent/devicelist.h
> 
> diff --git a/src/xenagent/devicelist.cpp b/src/xenagent/devicelist.cpp
> new file mode 100644
> index 0000000..5e948c1
> --- /dev/null
> +++ b/src/xenagent/devicelist.cpp
> @@ -0,0 +1,296 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <windows.h>
> +#include <string>
> +#include <setupapi.h>
> +#pragma comment (lib , "setupapi.lib" )
> +
> +#include "devicelist.h"
> +
> +// deal with SetupApi and RegisterDeviceNotification using different string
> types
> +static std::wstring Convert(const char* str)
> +{
> +    std::wstring wstr;
> +    wstr.reserve(strlen(str) + 1);
> +    MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)wstr.data(),
> (int)wstr.capacity());
> +    return wstr;
> +}
> +
> +static std::wstring Convert(const wchar_t* wstr)
> +{
> +    return std::wstring(wstr);
> +}
> +
> +CDevice::CDevice(const wchar_t* path) :
> +    m_handle(INVALID_HANDLE_VALUE), m_path(path), m_notify(NULL)
> +{
> +}
> +
> +/*virtual*/ CDevice::~CDevice()
> +{
> +    Close();
> +}
> +
> +const wchar_t* CDevice::Path() const
> +{
> +    return m_path.c_str();
> +}
> +
> +HANDLE CDevice::Open(HANDLE svc)
> +{
> +    Close();
> +
> +    m_handle = CreateFileW(m_path.c_str(),
> +                           GENERIC_READ | GENERIC_WRITE,
> +                           FILE_SHARE_READ | FILE_SHARE_WRITE,
> +                           NULL,
> +                           OPEN_EXISTING,
> +                           0,
> +                           NULL);
> +    if (m_handle == INVALID_HANDLE_VALUE)
> +        return INVALID_HANDLE_VALUE;
> +
> +    DEV_BROADCAST_HANDLE devhdl = { 0 };
> +    devhdl.dbch_size = sizeof(devhdl);
> +    devhdl.dbch_devicetype = DBT_DEVTYP_HANDLE;
> +    devhdl.dbch_handle = m_handle;
> +
> +    m_notify = RegisterDeviceNotification(svc, &devhdl,
> DEVICE_NOTIFY_SERVICE_HANDLE);
> +    if (m_notify == NULL) {
> +        Close();
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    return m_handle;
> +}
> +
> +void CDevice::Close()
> +{
> +    if (m_handle == INVALID_HANDLE_VALUE)
> +        return;
> +    CloseHandle(m_handle);
> +    m_handle = INVALID_HANDLE_VALUE;
> +}
> +
> +bool CDevice::Ioctl(DWORD ioctl, void* in, DWORD insz, void* out, DWORD
> outsz, DWORD* bytes /*= NULL*/)
> +{
> +    if (m_handle == INVALID_HANDLE_VALUE)
> +        return false;
> +
> +    DWORD _bytes;
> +    if (!DeviceIoControl(m_handle,
> +                         ioctl,
> +                         in,
> +                         insz,
> +                         out,
> +                         outsz,
> +                         (bytes == NULL) ? &_bytes : bytes,
> +                         NULL))
> +        return false;
> +
> +    return true;
> +}
> +
> +CDeviceList::CDeviceList(const GUID& itf) :
> +    m_guid(itf), m_notify(NULL), m_handle(NULL), m_impl(NULL)
> +{
> +}
> +
> +CDeviceList::~CDeviceList()
> +{
> +    Stop();
> +}
> +
> +bool CDeviceList::Start(HANDLE handle, IDeviceCreator* impl)
> +{
> +    Stop();
> +
> +    m_handle = handle;
> +    m_impl = impl;
> +
> +    DEV_BROADCAST_DEVICEINTERFACE dev = { 0 };
> +    dev.dbcc_size = sizeof(dev);
> +    dev.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
> +    dev.dbcc_classguid = m_guid;
> +
> +    m_notify = RegisterDeviceNotificationA(handle, &dev,
> DEVICE_NOTIFY_SERVICE_HANDLE);
> +    if (m_notify == NULL)
> +        return false;
> +
> +    HDEVINFO                            info;
> +    SP_DEVICE_INTERFACE_DATA            itf;
> +    PSP_DEVICE_INTERFACE_DETAIL_DATA    detail;
> +    ULONG                               idx;
> +    ULONG                               len;
> +
> +    info = SetupDiGetClassDevs(&m_guid,
> +                               NULL,
> +                               NULL,
> +                               DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
> +    if (info == INVALID_HANDLE_VALUE)
> +        return true; // non fatal, just missing already present device(s)
> +
> +    itf.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
> +    for (idx = 0;
> +        SetupDiEnumDeviceInterfaces(info, NULL, &m_guid, idx, &itf);
> +        ++idx) {
> +        SetupDiGetDeviceInterfaceDetail(info,
> +                                        &itf,
> +                                        NULL,
> +                                        0,
> +                                        &len,
> +                                        NULL);
> +        detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)new BYTE[len];
> +        if (detail == NULL)
> +            continue;
> +        detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
> +        if (SetupDiGetDeviceInterfaceDetail(info,
> +                                            &itf,
> +                                            detail,
> +                                            len,
> +                                            NULL,
> +                                            NULL)) {
> +            OnDeviceAdded(Convert((const char*)detail->DevicePath));
> +        }
> +        delete [] detail;
> +        itf.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
> +    }
> +    SetupDiDestroyDeviceInfoList(info);
> +    return true;
> +}
> +
> +void CDeviceList::Stop()
> +{
> +    if (m_notify != NULL)
> +        UnregisterDeviceNotification(m_notify);
> +    m_notify = NULL;
> +
> +    for (DeviceMap::iterator it = m_devs.begin();
> +            it != m_devs.end();
> +            ++it) {
> +        delete it->second;
> +    }
> +    m_devs.clear();
> +}
> +
> +void CDeviceList::OnDeviceEvent(DWORD evt, LPVOID data)
> +{
> +    PDEV_BROADCAST_HDR              hdr;
> +    PDEV_BROADCAST_DEVICEINTERFACE  itf;
> +    PDEV_BROADCAST_HANDLE           hdl;
> +
> +    hdr = (PDEV_BROADCAST_HDR)data;
> +    switch (evt) {
> +    case DBT_DEVICEARRIVAL:
> +        if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
> +            itf = (PDEV_BROADCAST_DEVICEINTERFACE)hdr;
> +            OnDeviceAdded(Convert((const wchar_t*)itf->dbcc_name));
> +        }
> +        break;
> +
> +    case DBT_DEVICEQUERYREMOVE:
> +        if (hdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {
> +            hdl = (PDEV_BROADCAST_HANDLE)hdr;
> +            OnDeviceQueryRemove(hdl->dbch_handle);
> +        }
> +        break;
> +
> +    case DBT_DEVICEREMOVEPENDING:
> +        if (hdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {
> +            hdl = (PDEV_BROADCAST_HANDLE)hdr;
> +            UnregisterDeviceNotification(hdl->dbch_hdevnotify);
> +            OnDeviceRemoved(hdl->dbch_handle);
> +        }
> +        break;
> +
> +    default:
> +        break;
> +    }
> +}
> +
> +CDevice* CDeviceList::GetFirstDevice()
> +{
> +    DeviceMap::iterator it = m_devs.begin();
> +    if (it == m_devs.end())
> +        return NULL;
> +    return it->second;
> +}
> +
> +void CDeviceList::OnDeviceAdded(const std::wstring& path)
> +{
> +    CDevice* dev;
> +    if (m_impl == NULL)
> +        dev = new CDevice(path.c_str());
> +    else
> +        dev = m_impl->Create(path.c_str());
> +    if (dev == NULL)
> +        return; // create failed
> +
> +    HANDLE handle = dev->Open(m_handle);
> +    if (handle == INVALID_HANDLE_VALUE) {
> +        delete dev;
> +        return; // open failed
> +    }
> +
> +    DeviceMap::iterator it = m_devs.find(handle);
> +    if (it != m_devs.end()) {
> +        delete dev;
> +        return;
> +    }
> +
> +    m_devs[handle] = dev;
> +    if (m_impl)
> +        m_impl->OnDeviceAdded(dev);
> +}
> +
> +void CDeviceList::OnDeviceQueryRemove(HANDLE handle)
> +{
> +    DeviceMap::iterator it = m_devs.find(handle);
> +    if (it == m_devs.end())
> +        return; // spurious event?
> +
> +    CDevice* dev = it->second;
> +    if (m_impl)
> +        m_impl->OnDeviceRemoved(dev);
> +    dev->Close();
> +}
> +
> +void CDeviceList::OnDeviceRemoved(HANDLE handle)
> +{
> +    DeviceMap::iterator it = m_devs.find(handle);
> +    if (it == m_devs.end())
> +        return; // spurious event?
> +
> +    CDevice* dev = it->second;
> +    delete dev;
> +    m_devs.erase(it);
> +}
> diff --git a/src/xenagent/devicelist.h b/src/xenagent/devicelist.h
> new file mode 100644
> index 0000000..a421e58
> --- /dev/null
> +++ b/src/xenagent/devicelist.h
> @@ -0,0 +1,92 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef __XENAGENT_DEVICELIST_H__
> +#define __XENAGENT_DEVICELIST_H__
> +
> +#include <windows.h>
> +#include <dbt.h>
> +#include <map>
> +#include <string>
> +
> +class CDevice
> +{
> +public:
> +    CDevice(const wchar_t* path);
> +    virtual ~CDevice();
> +
> +    const wchar_t* Path() const;
> +
> +    HANDLE Open(HANDLE svc);
> +    void Close();
> +
> +protected:
> +    bool Ioctl(DWORD ioctl, void* in, DWORD insz, void* out, DWORD outsz,
> DWORD* bytes = NULL);
> +
> +private:
> +    std::wstring    m_path;
> +    HANDLE          m_handle;
> +    HDEVNOTIFY      m_notify;
> +};
> +
> +interface IDeviceCreator
> +{
> +    virtual CDevice* Create(const wchar_t* path) = 0;
> +    virtual void OnDeviceAdded(CDevice* dev) = 0;
> +    virtual void OnDeviceRemoved(CDevice* dev) = 0;
> +};
> +
> +class CDeviceList
> +{
> +public:
> +    CDeviceList(const GUID& itf);
> +    ~CDeviceList();
> +
> +    bool Start(HANDLE svc, IDeviceCreator* impl);
> +    void Stop();
> +    void OnDeviceEvent(DWORD evt, LPVOID data);
> +    CDevice* GetFirstDevice();
> +
> +private:
> +    void OnDeviceAdded(const std::wstring& path);
> +    void OnDeviceQueryRemove(HANDLE handle);
> +    void OnDeviceRemoved(HANDLE dev);
> +
> +    typedef std::map< HANDLE, CDevice* > DeviceMap;
> +
> +    GUID        m_guid;
> +    DeviceMap   m_devs;
> +    HDEVNOTIFY  m_notify;
> +    HANDLE      m_handle;
> +    IDeviceCreator* m_impl;
> +};
> +
> +#endif
> diff --git a/src/xenagent/service.cpp b/src/xenagent/service.cpp
> index b794544..fec8e95 100644
> --- a/src/xenagent/service.cpp
> +++ b/src/xenagent/service.cpp
> @@ -151,7 +151,7 @@ static CXenAgent s_service;
>      return s_service.__ServiceControlHandlerEx(req, evt, data, ctxt);
>  }
> 
> -CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL)
> +CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL),
> m_devlist(GUID_INTERFACE_XENIFACE)
>  {
>      m_status.dwServiceType        = SERVICE_WIN32;
>      m_status.dwCurrentState       = SERVICE_START_PENDING;
> @@ -169,18 +169,36 @@ CXenAgent::~CXenAgent()
>      CloseHandle(m_svc_stop);
>  }
> 
> +/*virtual*/ CDevice* CXenAgent::Create(const wchar_t* path)
> +{
> +    return new CDevice(path);
> +}
> +
> +/*virtual*/ void CXenAgent::OnDeviceAdded(CDevice* dev)
> +{
> +    CXenAgent::Log("OnDeviceAdded(%ws)\n", dev->Path());
> +}
> +
> +/*virtual*/ void CXenAgent::OnDeviceRemoved(CDevice* dev)
> +{
> +    CXenAgent::Log("OnDeviceRemoved(%ws)\n", dev->Path());
> +}
> +
>  void CXenAgent::OnServiceStart()
>  {
>      CXenAgent::Log("OnServiceStart()\n");
> +    m_devlist.Start(m_handle, this);
>  }
> 
>  void CXenAgent::OnServiceStop()
>  {
>      CXenAgent::Log("OnServiceStop()\n");
> +    m_devlist.Stop();
>  }
> 
>  void CXenAgent::OnDeviceEvent(DWORD evt, LPVOID data)
>  {
> +    m_devlist.OnDeviceEvent(evt, data);
>  }
> 
>  bool CXenAgent::ServiceMainLoop()
> diff --git a/src/xenagent/service.h b/src/xenagent/service.h
> index 7446e41..ba3f430 100644
> --- a/src/xenagent/service.h
> +++ b/src/xenagent/service.h
> @@ -38,7 +38,9 @@
>  #define SVC_DISPLAYNAME PRODUCT_NAME_STR ## "Interface Service"
>  #define SVC_DESC "Monitors and provides various metrics to XenStore"
> 
> -class CXenAgent
> +#include "devicelist.h"
> +
> +class CXenAgent : public IDeviceCreator
>  {
>  public: // statics
>      static void Log(const char* fmt, ...);
> @@ -54,6 +56,11 @@ public: // ctor/dtor
>      CXenAgent();
>      ~CXenAgent();
> 
> +public: // IDeviceCreator
> +    virtual CDevice* Create(const wchar_t* path);
> +    virtual void OnDeviceAdded(CDevice* dev);
> +    virtual void OnDeviceRemoved(CDevice* dev);
> +
>  private: // service events
>      void OnServiceStart();
>      void OnServiceStop();
> @@ -69,6 +76,8 @@ private: // service support
>      SERVICE_STATUS_HANDLE   m_handle;
>      HANDLE                  m_evtlog;
>      HANDLE                  m_svc_stop;
> +
> +    CDeviceList             m_devlist;
>  };
> 
>  #endif
> diff --git a/vs2012/xenagent/xenagent.vcxproj
> b/vs2012/xenagent/xenagent.vcxproj
> index af99f9d..6c9c91c 100644
> --- a/vs2012/xenagent/xenagent.vcxproj
> +++ b/vs2012/xenagent/xenagent.vcxproj
> @@ -194,9 +194,11 @@
>    </ItemDefinitionGroup>
>    <ItemGroup>
>      <ClCompile Include="..\..\src\xenagent\service.cpp"/>
> +    <ClCompile Include="..\..\src\xenagent\devicelist.cpp"/>
>    </ItemGroup>
>    <ItemGroup>
>      <ClInclude Include="..\..\src\xenagent\service.h" />
> +    <ClInclude Include="..\..\src\xenagent\devicelist.h" />
>    </ItemGroup>
>    <ItemGroup>
>      <CustomBuild Include="..\..\src\xenagent\messages.mc">
> diff --git a/vs2013/xenagent/xenagent.vcxproj
> b/vs2013/xenagent/xenagent.vcxproj
> index 48ef3fc..d312626 100644
> --- a/vs2013/xenagent/xenagent.vcxproj
> +++ b/vs2013/xenagent/xenagent.vcxproj
> @@ -198,9 +198,11 @@
>    </ItemDefinitionGroup>
>    <ItemGroup>
>      <ClCompile Include="..\..\src\xenagent\service.cpp"/>
> +    <ClCompile Include="..\..\src\xenagent\devicelist.cpp"/>
>    </ItemGroup>
>    <ItemGroup>
>      <ClInclude Include="..\..\src\xenagent\service.h" />
> +    <ClInclude Include="..\..\src\xenagent\devicelist.h" />
>    </ItemGroup>
>    <ItemGroup>
>      <CustomBuild Include="..\..\src\xenagent\xenagent.mc">
> --
> 1.9.4.msysgit.1
> 
> 
> _______________________________________________
> win-pv-devel mailing list
> win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.