Add device sharing support

This commit is contained in:
Kyle Schwarz
2022-12-13 11:46:32 -05:00
parent 78465e0f20
commit a9157c82e5
46 changed files with 1946 additions and 102 deletions
+2 -2
View File
@@ -65,8 +65,8 @@ void FirmIO::Find(std::vector<FoundDevice>& found) {
memcpy(foundDevice.serial, serial->deviceSerial.c_str(), sizeof(foundDevice.serial) - 1);
foundDevice.serial[sizeof(foundDevice.serial) - 1] = '\0';
foundDevice.makeDriver = [](const device_eventhandler_t& report, neodevice_t&) {
return std::unique_ptr<Driver>(new FirmIO(report));
foundDevice.makeDriver = [](const device_eventhandler_t& report, neodevice_t& forDevice) {
return std::unique_ptr<Driver>(new FirmIO(report, forDevice));
};
found.push_back(foundDevice);
+1 -1
View File
@@ -47,7 +47,7 @@ void FTDI::Find(std::vector<FoundDevice>& found) {
}
}
FTDI::FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {
FTDI::FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err, forDevice) {
openable = strlen(forDevice.serial) > 0 && device.handle >= 0 && device.handle < (neodevice_handle_t)handles.size();
}
+1 -1
View File
@@ -200,7 +200,7 @@ bool PCAP::IsHandleValid(neodevice_handle_t handle) {
return (netifIndex < knownInterfaces.size());
}
PCAP::PCAP(device_eventhandler_t err, neodevice_t& forDevice) : Driver(err), device(forDevice), ethPacketizer(err) {
PCAP::PCAP(device_eventhandler_t err, neodevice_t& forDevice) : Driver(err, forDevice), ethPacketizer(err) {
if(IsHandleValid(device.handle)) {
iface = knownInterfaces[(device.handle >> 24) & 0xFF];
iface.fp = nullptr; // We're going to open our own connection to the interface. This should already be nullptr but just in case.
+65
View File
@@ -0,0 +1,65 @@
#include <iostream> // TODO: Remove later
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "icsneo/platform/posix/sharedmemory.h"
using namespace icsneo;
SharedMemory::~SharedMemory() {
close();
}
bool SharedMemory::open(const std::string& name, uint32_t size, bool create) {
if(create)
shm_unlink(name.c_str());
const auto fd = create ? shm_open(name.c_str(), O_CREAT | O_RDWR | O_EXCL, 0600) : shm_open(name.c_str(), O_RDWR, 0);
if(fd == -1) {
report(APIEvent::Type::SharedMemoryFailedToOpen, APIEvent::Severity::Error);
return false;
}
mName.emplace(name);
if(create && ftruncate(fd, size) == -1) {
report(APIEvent::Type::SharedMemoryFileTruncateError, APIEvent::Severity::Error);
close();
return false;
}
const auto shm = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shm == MAP_FAILED) {
report(APIEvent::Type::SharedMemoryMappingError, APIEvent::Severity::Error);
close();
return false;
}
mData.emplace(std::make_pair((uint8_t*)shm, size));
mCreated.emplace(create);
return true;
}
bool SharedMemory::close() {
bool failed = false;
if(mData) {
if(munmap((void*)mData->first, mData->second) == -1) {
report(APIEvent::Type::SharedMemoryUnmapError, APIEvent::Severity::EventWarning);
failed = true;
}
mData.reset();
}
if(mName && mCreated && *mCreated) {
if(shm_unlink(mName->c_str()) == -1) {
report(APIEvent::Type::SharedMemoryFailedToUnlink, APIEvent::Severity::EventWarning);
failed = true;
}
mName.reset();
}
if(failed)
report(APIEvent::Type::SharedMemoryFailedToClose, APIEvent::Severity::Error);
return !failed;
}
uint8_t* SharedMemory::data() {
if(!mData) {
report(APIEvent::Type::SharedMemoryDataIsNull, APIEvent::Severity::Error);
return nullptr;
}
return mData->first;
}
+99
View File
@@ -0,0 +1,99 @@
#include <iostream> // TODO: Remove later
#include <fcntl.h>
#include "icsneo/platform/posix/sharedsemaphore.h"
using namespace icsneo;
SharedSemaphore::~SharedSemaphore() {
close();
}
bool SharedSemaphore::open(const std::string& name, bool create, unsigned initialCount) {
const auto slashPrefixed = "/" + name;
if(create)
sem_unlink(slashPrefixed.c_str()); // try clean-up, it's fine if it errors
const auto sem = create ? sem_open(slashPrefixed.c_str(), O_CREAT | O_EXCL, 0600, initialCount) : sem_open(slashPrefixed.c_str(), 0);
if(sem == SEM_FAILED) {
report(APIEvent::Type::SharedSemaphoreFailedToOpen, APIEvent::Severity::Error);
return false;
}
mName.emplace(slashPrefixed);
semaphore.emplace(sem);
created.emplace(create);
return true;
}
bool SharedSemaphore::close() {
closing = true;
post(); // wake any waiting
bool failed = false;
if(semaphore) {
if(sem_close(semaphore.value()) == -1) {
report(APIEvent::Type::SharedSemaphoreFailedToClose, APIEvent::Severity::Error);
failed = true;
}
semaphore.reset();
}
if(mName && created && *created) {
if(sem_unlink(mName->c_str()) == -1) {
report(APIEvent::Type::SharedSemaphoreFailedToUnlink, APIEvent::Severity::Error);
failed = true;
}
mName.reset();
}
return !failed;
}
bool SharedSemaphore::wait(const std::chrono::milliseconds& timeout) {
if(!semaphore) {
report(APIEvent::Type::SharedSemaphoreNotOpenForWait, APIEvent::Severity::Error);
return false;
}
const auto timedwait = [&]() -> bool {
#if defined(__MACH__)
// TODO: Quite inefficient due to Darwin's lack of sem_timedwait()
const auto tryTill = std::chrono::steady_clock::now() + timeout;
while (std::chrono::steady_clock::now() <= tryTill) {
if(sem_trywait(*semaphore) == 0)
return true;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return false;
#else // UNIX
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += static_cast<unsigned int>(timeout.count() / 1000);
ts.tv_nsec += static_cast<int>((timeout.count() % 1000) * 1000000);
// potentially promote another second
if(ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
return sem_timedwait(*semaphore, &ts) != -1;
#endif
};
if(!timedwait()) {
if(errno == ETIMEDOUT)
return false; // unable to lock within timeout
if(errno != EINTR) // we don't need a warning for this
report(APIEvent::Type::SharedSemaphoreFailedToWait, APIEvent::Severity::Error);
return false;
}
if(closing)
return false; // we were woken by close()
return true;
}
bool SharedSemaphore::post() {
if(!semaphore) {
report(APIEvent::Type::SharedSemaphoreNotOpenForPost, APIEvent::Severity::Error);
return false;
}
if(sem_post(*semaphore) == -1) {
report(APIEvent::Type::SharedSemaphoreFailedToPost, APIEvent::Severity::Error);
return false;
}
return true;
}
+3 -3
View File
@@ -166,8 +166,8 @@ void PCAP::Find(std::vector<FoundDevice>& found) {
memcpy(foundDevice.serial, serial->deviceSerial.c_str(), sizeof(foundDevice.serial) - 1);
foundDevice.serial[sizeof(foundDevice.serial) - 1] = '\0';
foundDevice.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& device) {
return std::unique_ptr<Driver>(new PCAP(reportFn, device));
foundDevice.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& forDevice) {
return std::unique_ptr<Driver>(new PCAP(reportFn, forDevice));
};
found.push_back(foundDevice);
@@ -184,7 +184,7 @@ bool PCAP::IsHandleValid(neodevice_handle_t handle) {
return (netifIndex < knownInterfaces.size());
}
PCAP::PCAP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice), pcap(PCAPDLL::getInstance()), ethPacketizer(err) {
PCAP::PCAP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err, forDevice), pcap(PCAPDLL::getInstance()), ethPacketizer(err) {
if(IsHandleValid(device.handle)) {
iface = knownInterfaces[(device.handle >> 24) & 0xFF];
iface.fp = nullptr; // We're going to open our own connection to the interface. This should already be nullptr but just in case.
+47
View File
@@ -0,0 +1,47 @@
#include "icsneo/api/event.h"
#include "icsneo/platform/windows/sharedmemory.h"
using namespace icsneo;
SharedMemory::~SharedMemory() {
close();
}
bool SharedMemory::open(const std::string& name, uint32_t size, bool create) {
HANDLE shm;
if(create)
shm = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, name.c_str());
else
shm = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name.c_str());
if(shm == NULL) {
report(APIEvent::Type::SharedMemoryFailedToOpen, APIEvent::Severity::Error);
return false;
}
mHandle.emplace(shm);
const auto dataStart = MapViewOfFile(shm, FILE_MAP_ALL_ACCESS, 0, 0, size);
if(dataStart == NULL) {
report(APIEvent::Type::SharedMemoryMappingError, APIEvent::Severity::Error);
close();
return false;
}
mData.emplace(std::make_pair((uint8_t*)dataStart, size));
mCreated.emplace(create);
return true;
}
bool SharedMemory::close() {
bool failed = false; // TODO: need to close properly
if(failed) {
report(APIEvent::Type::SharedMemoryFailedToClose, APIEvent::Severity::Error);
}
return !failed;
}
uint8_t* SharedMemory::data() {
if(!mData) {
report(APIEvent::Type::SharedMemoryDataIsNull, APIEvent::Severity::Error);
return nullptr;
}
return mData->first;
}
+65
View File
@@ -0,0 +1,65 @@
#include "icsneo/platform/windows/sharedsemaphore.h"
using namespace icsneo;
SharedSemaphore::~SharedSemaphore() {
close();
}
bool SharedSemaphore::open(const std::string& name, bool create, unsigned initialCount) {
HANDLE sem;
if(create)
sem = CreateSemaphore(NULL, initialCount, LONG_MAX, name.c_str());
else
sem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name.c_str());
if(sem == NULL) {
report(APIEvent::Type::SharedSemaphoreFailedToOpen, APIEvent::Severity::Error);
return false;
}
semaphore.emplace(sem);
created.emplace(create);
return true;
}
bool SharedSemaphore::close() {
if(!semaphore)
return false;
closing = true;
post(); // wake any waiting
if(CloseHandle(*semaphore) == 0) {
report(APIEvent::Type::SharedSemaphoreFailedToClose, APIEvent::Severity::Error);
return false;
}
semaphore.reset();
return true;
}
bool SharedSemaphore::wait(const std::chrono::milliseconds& timeout) {
if(!semaphore) {
report(APIEvent::Type::SharedSemaphoreNotOpenForWait, APIEvent::Severity::Error);
return false;
}
if(WaitForSingleObject(*semaphore, static_cast<DWORD>(timeout.count())) != 0) {
report(APIEvent::Type::SharedSemaphoreFailedToWait, APIEvent::Severity::Error);
return false;
}
if(closing)
return false; // we were woken by close()
return true;
}
bool SharedSemaphore::post() {
if(!semaphore) {
report(APIEvent::Type::SharedSemaphoreNotOpenForPost, APIEvent::Severity::Error);
return false;
}
if(ReleaseSemaphore(*semaphore, 1, NULL) == 0) {
report(APIEvent::Type::SharedSemaphoreFailedToPost, APIEvent::Severity::Error);
return false;
}
return true;
}
+1 -1
View File
@@ -192,7 +192,7 @@ void VCP::Find(std::vector<FoundDevice>& found, std::vector<std::wstring> driver
}
}
VCP::VCP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {
VCP::VCP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err, forDevice) {
detail = std::make_shared<Detail>();
}