diff --git a/src/interprocess.cpp b/src/interprocess.cpp index e686069a..0441f60d 100644 --- a/src/interprocess.cpp +++ b/src/interprocess.cpp @@ -1,51 +1,223 @@ -/** - * @file globals.cpp - * @brief Implementation for globally accessible variables and functions. - */ -#include "interprocess.h" -#include "logging.h" +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ -#include -#include -#include -#include -#include #include -#pragma comment(lib, "user32.lib") +#include +#include +#include +#include +#include "interprocess.h" +IVSHMEM * IVSHMEM::m_instance = NULL; - -void* -map_file(char* name) +IVSHMEM::IVSHMEM() : + m_initialized(false), + m_handle(INVALID_HANDLE_VALUE), + m_gotSize(false), + m_gotPeerID(false), + m_gotMemory(false) { - HANDLE hMapFile; - hMapFile = OpenFileMappingA( - FILE_MAP_ALL_ACCESS, // read/write access - FALSE, // do not inherit the name - name); // name of mapping object +} - if (hMapFile == NULL) { - BOOST_LOG(error) << "Could not open file mapping object " << GetLastError(); - return nullptr; - } +IVSHMEM::~IVSHMEM() +{ + DeInitialize(); +} - void* pBuf = MapViewOfFile(hMapFile, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - sizeof(Queue)); +bool IVSHMEM::Initialize() +{ + if (m_initialized) + DeInitialize(); - if (pBuf == NULL) { - BOOST_LOG(error) << "Could not map view of file (%d) " << GetLastError(); - CloseHandle(hMapFile); - return nullptr; + HDEVINFO deviceInfoSet; + PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + + deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE); + ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + while (true) + { + if (SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &GUID_DEVINTERFACE_IVSHMEM, 0, &deviceInterfaceData) == FALSE) + { + DWORD error = GetLastError(); + if (error == ERROR_NO_MORE_ITEMS) + { + printf("Unable to enumerate the device, is it attached?"); + break; + } + + printf("SetupDiEnumDeviceInterfaces failed"); + break; } - return pBuf; + DWORD reqSize = 0; + SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &reqSize, NULL); + if (!reqSize) + { + printf("SetupDiGetDeviceInterfaceDetail"); + break; + } + + infData = static_cast(malloc(reqSize)); + ZeroMemory(infData, reqSize); + infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, infData, reqSize, NULL, NULL)) + { + printf("SetupDiGetDeviceInterfaceDetail"); + break; + } + + m_handle = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0); + if (m_handle == INVALID_HANDLE_VALUE) + { + printf("CreateFile returned INVALID_HANDLE_VALUE"); + break; + } + + m_initialized = true; + break; + } + + if (infData) + free(infData); + + SetupDiDestroyDeviceInfoList(deviceInfoSet); + return m_initialized; +} + +void IVSHMEM::DeInitialize() +{ + if (!m_initialized) + return; + + if (m_gotMemory) + { + if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL)) + printf("DeviceIoControl failed: %d", (int)GetLastError()); + m_memory = NULL; + } + + if (m_handle != INVALID_HANDLE_VALUE) + CloseHandle(m_handle); + + m_initialized = false; + m_handle = INVALID_HANDLE_VALUE; + m_gotSize = false; + m_gotPeerID = false; + m_gotMemory = false; +} + +bool IVSHMEM::IsInitialized() +{ + return m_initialized; +} + +UINT64 IVSHMEM::GetSize() +{ + if (!m_initialized) + return 0; + + if (m_gotSize) + return m_size; + + IVSHMEM_SIZE size; + if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(IVSHMEM_SIZE), NULL, NULL)) + { + printf("DeviceIoControl Failed: %d", (int)GetLastError()); + return 0; + } + + m_gotSize = true; + m_size = static_cast(size); + return m_size; +} + +UINT16 IVSHMEM::GetPeerID() +{ + if (!m_initialized) + return 0; + + if (m_gotPeerID) + return m_peerID; + + IVSHMEM_PEERID peerID; + if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &peerID, sizeof(IVSHMEM_PEERID), NULL, NULL)) + { + printf("DeviceIoControl Failed: %d", (int)GetLastError()); + return 0; + } + + m_gotPeerID = true; + m_peerID = static_cast(peerID); + return m_peerID; +} + + +void * IVSHMEM::GetMemory() +{ + if (!m_initialized) + return NULL; + + if (m_gotMemory) + return m_memory; + +// this if define can be removed later once everyone is un the latest version +// old versions of the IVSHMEM driver ignore the input argument, as such this +// is completely backwards compatible +#if defined(IVSHMEM_CACHE_WRITECOMBINED) + IVSHMEM_MMAP_CONFIG config; + config.cacheMode = IVSHMEM_CACHE_WRITECOMBINED; +#endif + + IVSHMEM_MMAP map; + ZeroMemory(&map, sizeof(IVSHMEM_MMAP)); + if (!DeviceIoControl( + m_handle, + IOCTL_IVSHMEM_REQUEST_MMAP, +#if defined(IVSHMEM_CACHE_WRITECOMBINED) + &config, sizeof(IVSHMEM_MMAP_CONFIG), +#else + NULL , 0, +#endif + &map , sizeof(IVSHMEM_MMAP ), + NULL, NULL)) + { + printf("DeviceIoControl Failed: %d", (int)GetLastError()); + return NULL; + } + + m_gotSize = true; + m_gotPeerID = true; + m_gotMemory = true; + m_size = static_cast(map.size ); + m_peerID = static_cast(map.peerID ); + m_memory = map.ptr; + + return m_memory; +} + + + +HANDLE IVSHMEM::getHandle() +{ + return m_handle; } -Queue* -init_shared_memory(char* data){ - Queue* memory = (Queue*)map_file(data); - return memory; -} \ No newline at end of file diff --git a/src/interprocess.h b/src/interprocess.h index a265bcc5..27634a6f 100644 --- a/src/interprocess.h +++ b/src/interprocess.h @@ -1,14 +1,127 @@ -/** - * @file globals.h - * @brief Header for globally accessible variables and functions. - */ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #pragma once -#include "thread_pool.h" -#include "thread_safe.h" +#include +#include +#include -#include +DEFINE_GUID (GUID_DEVINTERFACE_IVSHMEM, + 0xdf576976,0x569d,0x4672,0x95,0xa0,0xf5,0x7e,0x4e,0xa0,0xb2,0x10); +// {df576976-569d-4672-95a0-f57e4ea0b210} + +typedef UINT16 IVSHMEM_PEERID; +typedef UINT64 IVSHMEM_SIZE; + +#define IVSHMEM_CACHE_NONCACHED 0 +#define IVSHMEM_CACHE_CACHED 1 +#define IVSHMEM_CACHE_WRITECOMBINED 2 + +/* + This structure is for use with the IOCTL_IVSHMEM_REQUEST_MMAP IOCTL +*/ +typedef struct IVSHMEM_MMAP_CONFIG +{ + UINT8 cacheMode; // the caching mode of the mapping, see IVSHMEM_CACHE_* for options +} +IVSHMEM_MMAP_CONFIG, *PIVSHMEM_MMAP_CONFIG; + +/* + This structure is for use with the IOCTL_IVSHMEM_REQUEST_MMAP IOCTL +*/ +typedef struct IVSHMEM_MMAP +{ + IVSHMEM_PEERID peerID; // our peer id + IVSHMEM_SIZE size; // the size of the memory region + PVOID ptr; // pointer to the memory region + UINT16 vectors; // the number of vectors available +} +IVSHMEM_MMAP, *PIVSHMEM_MMAP; + +/* + This structure is for use with the IOCTL_IVSHMEM_RING_DOORBELL IOCTL +*/ +typedef struct IVSHMEM_RING +{ + IVSHMEM_PEERID peerID; // the id of the peer to ring + UINT16 vector; // the doorbell to ring +} +IVSHMEM_RING, *PIVSHMEM_RING; + +/* + This structure is for use with the IOCTL_IVSHMEM_REGISTER_EVENT IOCTL + + Please Note: + - The IVSHMEM driver has a hard limit of 32 events. + - Events that are singleShot are released after they have been set. + - At this time repeating events are only released when the driver device + handle is closed, closing the event handle doesn't release it from the + drivers list. While this won't cause a problem in the driver, it will + cause you to run out of event slots. + */ +typedef struct IVSHMEM_EVENT +{ + UINT16 vector; // the vector that triggers the event + HANDLE event; // the event to trigger + BOOLEAN singleShot; // set to TRUE if you want the driver to only trigger this event once +} +IVSHMEM_EVENT, *PIVSHMEM_EVENT; + +#define IOCTL_IVSHMEM_REQUEST_PEERID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IVSHMEM_REQUEST_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IVSHMEM_REQUEST_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IVSHMEM_RELEASE_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IVSHMEM_RING_DOORBELL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IVSHMEM_REGISTER_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) -Queue* -init_shared_memory(char* data); \ No newline at end of file +class IVSHMEM +{ +public: + IVSHMEM(); + ~IVSHMEM(); + + static IVSHMEM * Get() + { + if (!m_instance) + m_instance = new IVSHMEM(); + return m_instance; + } + + bool Initialize(); + void DeInitialize(); + bool IsInitialized(); + + UINT64 GetSize(); + UINT16 GetPeerID(); + void * GetMemory(); + HANDLE getHandle(); + +protected: + + +private: + static IVSHMEM * m_instance; + bool m_initialized; + HANDLE m_handle; + UINT64 m_size ; bool m_gotSize ; + UINT16 m_peerID ; bool m_gotPeerID; + void * m_memory ; bool m_gotMemory; +}; diff --git a/src/main.cpp b/src/main.cpp index 540937f8..031b1138 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // local includes #include "globals.h" @@ -138,16 +139,14 @@ main(int argc, char *argv[]) { queuetype = QueueType::Audio; int codec = 0; - char* shmid; - if (argc == 4) { + if (argc == 3) { std::stringstream ss1; ss1 << argv[2]; std::string codecs; ss1 >> codecs; - shmid = argv[3]; if (codecs == "h265") codec = 1; else if (codecs == "av1") codec = 2; - } else shmid = argv[2]; + } @@ -176,8 +175,12 @@ main(int argc, char *argv[]) { #endif } + auto platf_deinit_guard = platf::init(); - auto queue = init_shared_memory(shmid); + + + IVSHMEM* ivshmem = new IVSHMEM(); + auto queue = (Queue*)ivshmem->GetMemory(); if (!platf_deinit_guard) { BOOST_LOG(error) << "Platform failed to initialize"sv; return StatusCode::NO_ENCODER_AVAILABLE;