[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 06/20] Add DeviceList
CDeviceList manages the device change notifications, and SetupApi enumeration. Add a class inherited from CDevice and implement IDeviceCreator to add specific functionality Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- src/liteagent/DeviceList.cpp | 279 +++++++++++++++++++++++++++++++++++++ src/liteagent/DeviceList.h | 89 ++++++++++++ src/liteagent/LiteAgent.cpp | 12 +- src/liteagent/LiteAgent.h | 9 +- vs2012/liteagent/LiteAgent.vcxproj | 2 + vs2013/liteagent/LiteAgent.vcxproj | 2 + 6 files changed, 391 insertions(+), 2 deletions(-) create mode 100644 src/liteagent/DeviceList.cpp create mode 100644 src/liteagent/DeviceList.h diff --git a/src/liteagent/DeviceList.cpp b/src/liteagent/DeviceList.cpp new file mode 100644 index 0000000..1cb3bf6 --- /dev/null +++ b/src/liteagent/DeviceList.cpp @@ -0,0 +1,279 @@ +/* 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) +{ +} + +CDevice::~CDevice() +{ + Close(); +} + +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) +{ + if (m_handle == INVALID_HANDLE_VALUE) + return false; + + if (!DeviceIoControl(m_handle, ioctl, in, insz, out, outsz, 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; +} + +void CDeviceList::OnDeviceQueryRemove(HANDLE handle) +{ + DeviceMap::iterator it = m_devs.find(handle); + if (it == m_devs.end()) + return; // spurious event? + + CDevice* dev = it->second; + 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/liteagent/DeviceList.h b/src/liteagent/DeviceList.h new file mode 100644 index 0000000..10df546 --- /dev/null +++ b/src/liteagent/DeviceList.h @@ -0,0 +1,89 @@ +/* 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 _DEVICELIST_H_ +#define _DEVICELIST_H_ + +#include <windows.h> +#include <dbt.h> +#include <map> +#include <string> + +class CDevice +{ +public: + CDevice(const wchar_t* path); + ~CDevice(); + + HANDLE Open(HANDLE svc); + void Close(); + +protected: + bool Ioctl(DWORD ioctl, void* in, DWORD insz, void* out, DWORD outsz, DWORD* bytes); + +private: + std::wstring m_path; + HANDLE m_handle; + HDEVNOTIFY m_notify; +}; + +interface IDeviceCreator +{ + virtual CDevice* Create(const wchar_t* path) = 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/liteagent/LiteAgent.cpp b/src/liteagent/LiteAgent.cpp index 7920e9b..1eec87e 100644 --- a/src/liteagent/LiteAgent.cpp +++ b/src/liteagent/LiteAgent.cpp @@ -33,6 +33,7 @@ #include <windows.h> #include "LiteAgent.h" +#include "xeniface_ioctls.h" int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE ignore, LPSTR lpCmdLine, int nCmdShow) { @@ -87,6 +88,7 @@ static CLiteAgent s_service; DeleteService(svc); CloseServiceHandle(svc); CloseServiceHandle(mgr); + return 0; } /*static*/ int CLiteAgent::ServiceEntry() @@ -114,7 +116,7 @@ static CLiteAgent s_service; return s_service.__ServiceControlHandlerEx(req, evt, data, ctxt); } -CLiteAgent::CLiteAgent() : m_handle(NULL) +CLiteAgent::CLiteAgent() : m_handle(NULL), m_devs(GUID_INTERFACE_XENIFACE) { m_status.dwServiceType = SERVICE_WIN32; m_status.dwCurrentState = SERVICE_START_PENDING; @@ -132,19 +134,27 @@ CLiteAgent::~CLiteAgent() CloseHandle(m_svc_stop); } +/*virtual*/ CDevice* CLiteAgent::Create(const wchar_t* path) +{ + return new CDevice(path); +} + void CLiteAgent::OnServiceStart() { CLiteAgent::Log("OnServiceStart()\n"); + m_devs.Start(m_handle, this); } void CLiteAgent::OnServiceStop() { CLiteAgent::Log("OnServiceStop()\n"); + m_devs.Stop(); } void CLiteAgent::OnDeviceEvent(DWORD evt, LPVOID data) { CLiteAgent::Log("OnDeviceEvent()\n"); + m_devs.OnDeviceEvent(evt, data); } bool CLiteAgent::ServiceMainLoop() diff --git a/src/liteagent/LiteAgent.h b/src/liteagent/LiteAgent.h index ab192ef..57ed9e7 100644 --- a/src/liteagent/LiteAgent.h +++ b/src/liteagent/LiteAgent.h @@ -38,7 +38,9 @@ #define SVC_DISPLAYNAME PRODUCT_NAME_STR ## "Interface Service" #define SVC_DESC "Monitors and provides various metrics to XenStore" -class CLiteAgent +#include "DeviceList.h" + +class CLiteAgent : public IDeviceCreator { public: // statics static void Log(const char* fmt, ...); @@ -54,6 +56,9 @@ public: // ctor/dtor CLiteAgent(); ~CLiteAgent(); +public: // IDeviceCreator + virtual CDevice* Create(const wchar_t* path); + private: // service events void OnServiceStart(); void OnServiceStop(); @@ -68,6 +73,8 @@ private: // service support SERVICE_STATUS m_status; SERVICE_STATUS_HANDLE m_handle; HANDLE m_svc_stop; + + CDeviceList m_devs; }; #endif diff --git a/vs2012/liteagent/LiteAgent.vcxproj b/vs2012/liteagent/LiteAgent.vcxproj index 967a3a1..84b5113 100644 --- a/vs2012/liteagent/LiteAgent.vcxproj +++ b/vs2012/liteagent/LiteAgent.vcxproj @@ -194,9 +194,11 @@ </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\src\liteagent\LiteAgent.cpp" /> + <ClCompile Include="..\..\src\liteagent\DeviceList.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\src\liteagent\LiteAgent.h" /> + <ClInclude Include="..\..\src\liteagent\DeviceList.h" /> </ItemGroup> <ItemGroup> <CustomBuild Include="..\..\src\liteagent\messages.mc"> diff --git a/vs2013/liteagent/LiteAgent.vcxproj b/vs2013/liteagent/LiteAgent.vcxproj index c1b5c5d..6a3c787 100644 --- a/vs2013/liteagent/LiteAgent.vcxproj +++ b/vs2013/liteagent/LiteAgent.vcxproj @@ -198,9 +198,11 @@ </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\src\liteagent\LiteAgent.cpp" /> + <ClCompile Include="..\..\src\liteagent\DeviceList.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\src\liteagent\LiteAgent.h" /> + <ClInclude Include="..\..\src\liteagent\DeviceList.h" /> </ItemGroup> <ItemGroup> <CustomBuild Include="..\..\src\liteagent\messages.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 |