[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |