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

[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>
---
 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

 


Rackspace

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