mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-11-04 12:59:07 +01:00
All: Remove deprecated Drivers
This commit is contained in:
@@ -1,244 +0,0 @@
|
||||
#include "icsneo/platform/windows/cdcacm.h"
|
||||
|
||||
#include <setupapi.h>
|
||||
#include <initguid.h>
|
||||
#include <usbiodef.h>
|
||||
#include <devpkey.h>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
#define SERIAL_SIZE 6
|
||||
|
||||
CDCACM::CDCACM(const device_eventhandler_t& err, const std::wstring& path) : Driver(err), path(path) {
|
||||
}
|
||||
|
||||
bool CDCACM::open() {
|
||||
handle = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
|
||||
if(handle == INVALID_HANDLE_VALUE) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
COMMTIMEOUTS timeouts;
|
||||
timeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 0;
|
||||
timeouts.WriteTotalTimeoutConstant = 0;
|
||||
|
||||
if(!SetCommTimeouts(handle, &timeouts)) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
DCB comstate;
|
||||
if(!GetCommState(handle, &comstate)) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
comstate.BaudRate = 115200;
|
||||
comstate.ByteSize = 8;
|
||||
comstate.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
if(!SetCommState(handle, &comstate)) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
PurgeComm(handle, PURGE_RXCLEAR);
|
||||
|
||||
readOverlapped.hEvent = CreateEventA(nullptr, false, false, nullptr);
|
||||
writeOverlapped.hEvent = CreateEventA(nullptr, false, false, nullptr);
|
||||
|
||||
setIsDisconnected(false);
|
||||
readThread = std::thread(&CDCACM::read, this);
|
||||
writeThread = std::thread(&CDCACM::write, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDCACM::isOpen() {
|
||||
return handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
bool CDCACM::close() {
|
||||
setIsClosing(true);
|
||||
SetEvent(readOverlapped.hEvent); // unblock read thread
|
||||
SetEvent(writeOverlapped.hEvent); // unblock write thread if waiting on COM write
|
||||
writeQueue.enqueue(WriteOperation{}); // unblock write thread if waiting on write queue pop
|
||||
readThread.join();
|
||||
writeThread.join();
|
||||
CloseHandle(readOverlapped.hEvent);
|
||||
CloseHandle(writeOverlapped.hEvent);
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
setIsClosing(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDCACM::read() {
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
|
||||
std::vector<uint8_t> buffer(ICSNEO_DRIVER_RINGBUFFER_SIZE);
|
||||
|
||||
while(!isDisconnected() && !isClosing()) {
|
||||
if(!ReadFile(handle, buffer.data(), (DWORD)buffer.size(), nullptr, &readOverlapped)) {
|
||||
if(GetLastError() != ERROR_IO_PENDING) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
setIsDisconnected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DWORD read = 0;
|
||||
if(!GetOverlappedResult(handle, &readOverlapped, &read, true)) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
setIsDisconnected(true);
|
||||
return;
|
||||
}
|
||||
if(read == 0) {
|
||||
continue;
|
||||
}
|
||||
while(!isDisconnected() && !isClosing()) {
|
||||
if(pushRx(buffer.data(), read))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDCACM::write() {
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
|
||||
WriteOperation writeOp;
|
||||
|
||||
while(!isDisconnected() && !isClosing()) {
|
||||
writeQueue.wait_dequeue(writeOp);
|
||||
|
||||
if(isDisconnected() || isClosing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!WriteFile(handle, writeOp.bytes.data(), (DWORD)writeOp.bytes.size(), nullptr, &writeOverlapped)) {
|
||||
if(GetLastError() != ERROR_IO_PENDING) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
setIsDisconnected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DWORD written;
|
||||
if(!GetOverlappedResult(handle, &writeOverlapped, &written, true)) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
setIsDisconnected(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if(written != writeOp.bytes.size()) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
|
||||
setIsDisconnected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DeviceInfo {
|
||||
public:
|
||||
DeviceInfo() {
|
||||
mDeviceInfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
}
|
||||
~DeviceInfo() {
|
||||
SetupDiDestroyDeviceInfoList(mDeviceInfo);
|
||||
}
|
||||
operator HDEVINFO() const {
|
||||
return mDeviceInfo;
|
||||
}
|
||||
operator bool() const {
|
||||
return mDeviceInfo != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
private:
|
||||
HDEVINFO mDeviceInfo;
|
||||
};
|
||||
|
||||
class DeviceInfoData {
|
||||
public:
|
||||
DeviceInfoData() {
|
||||
mDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
}
|
||||
operator SP_DEVINFO_DATA*() {
|
||||
return &mDeviceInfoData;
|
||||
}
|
||||
private:
|
||||
SP_DEVINFO_DATA mDeviceInfoData;
|
||||
};
|
||||
|
||||
static constexpr size_t WSTRING_ELEMENT_SIZE = sizeof(std::wstring::value_type);
|
||||
|
||||
void CDCACM::Find(std::vector<FoundDevice>& found) {
|
||||
DeviceInfoData deviceInfoData;
|
||||
const std::wstring intrepidUSB(L"USB\\VID_093C");
|
||||
DeviceInfo deviceInfoSet;
|
||||
if(!deviceInfoSet) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
for(DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoSet, i, deviceInfoData); ++i) {
|
||||
DWORD DataT;
|
||||
DWORD buffersize = 0;
|
||||
|
||||
std::wstring wclass;
|
||||
while(!SetupDiGetDevicePropertyW(deviceInfoSet, deviceInfoData, &DEVPKEY_Device_Class, &DataT, reinterpret_cast<PBYTE>(wclass.data()), static_cast<DWORD>((wclass.size() + 1) * WSTRING_ELEMENT_SIZE), &buffersize, 0)) {
|
||||
wclass.resize((buffersize - 1) / WSTRING_ELEMENT_SIZE);
|
||||
}
|
||||
|
||||
if(wclass != L"Ports") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: is this a bug in Windows? why is this returned size different/wrong? It's like it's not a wstring at all
|
||||
std::wstring deviceInstanceId;
|
||||
while(!SetupDiGetDeviceInstanceIdW(deviceInfoSet, deviceInfoData, deviceInstanceId.data(), static_cast<DWORD>(deviceInstanceId.size() + 1), &buffersize)) {
|
||||
deviceInstanceId.resize(buffersize - 1);
|
||||
}
|
||||
|
||||
if(deviceInstanceId.find(intrepidUSB) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto serialOffset = deviceInstanceId.find_last_of('\\');
|
||||
|
||||
if(serialOffset == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++serialOffset; // move past '\'
|
||||
|
||||
if(deviceInstanceId.size() < serialOffset + SERIAL_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::wstring wserial(deviceInstanceId.c_str() + serialOffset, SERIAL_SIZE);
|
||||
|
||||
FoundDevice device = {0};
|
||||
|
||||
if(WideCharToMultiByte(CP_ACP, 0, wserial.c_str(), (int)wserial.size(), device.serial, SERIAL_SIZE, NULL, NULL) == 0) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::wstring wport;
|
||||
while(!SetupDiGetCustomDevicePropertyW(deviceInfoSet, deviceInfoData, L"PortName", 0, &DataT, reinterpret_cast<PBYTE>(wport.data()), static_cast<DWORD>((wport.size() + 1) * WSTRING_ELEMENT_SIZE), &buffersize)) {
|
||||
wport.resize((buffersize - 1) / WSTRING_ELEMENT_SIZE);
|
||||
}
|
||||
|
||||
const std::wstring path(L"\\\\.\\" + wport);
|
||||
|
||||
device.makeDriver = [path](device_eventhandler_t err, neodevice_t&) {
|
||||
return std::make_unique<CDCACM>(err, path);
|
||||
};
|
||||
|
||||
found.emplace_back(std::move(device));
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "icsneo/platform/windows/internal/pcapdll.h"
|
||||
#include <tchar.h>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
const PCAPDLL& PCAPDLL::getInstance()
|
||||
{
|
||||
static PCAPDLL instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
PCAPDLL::~PCAPDLL()
|
||||
{
|
||||
closeDLL();
|
||||
}
|
||||
|
||||
void PCAPDLL::closeDLL()
|
||||
{
|
||||
if (dll)
|
||||
FreeLibrary(dll);
|
||||
dll = nullptr;
|
||||
}
|
||||
|
||||
bool PCAPDLL::ok() const
|
||||
{
|
||||
return dll != nullptr;
|
||||
}
|
||||
|
||||
PCAPDLL::PCAPDLL()
|
||||
{
|
||||
TCHAR dir[512] = {0};
|
||||
if(GetSystemDirectory(dir, 480)) {
|
||||
_tcscat_s(dir, 512, TEXT("\\Npcap"));
|
||||
if(SetDllDirectory(dir)) {
|
||||
// will search for Npcap first, then fall back to WinPcap
|
||||
dll = LoadLibrary(TEXT("wpcap.dll"));
|
||||
SetDllDirectory(nullptr); // reset
|
||||
}
|
||||
}
|
||||
|
||||
if(dll == NULL) {
|
||||
closeDLL();
|
||||
} else {
|
||||
findalldevs_ex = (PCAPFINDDEVICE)GetProcAddress(dll, "pcap_findalldevs_ex");
|
||||
open = (PCAPOPEN)GetProcAddress(dll, "pcap_open");
|
||||
freealldevs = (PCAPFREEDEVS)GetProcAddress(dll, "pcap_freealldevs");
|
||||
close = (PCAPCLOSE)GetProcAddress(dll, "pcap_close");
|
||||
stats = (PCAPSTATS)GetProcAddress(dll, "pcap_stats");
|
||||
next_ex = (PCAPNEXTEX)GetProcAddress(dll, "pcap_next_ex");
|
||||
sendpacket = (PCAPSENDPACKET)GetProcAddress(dll, "pcap_sendpacket");
|
||||
sendqueue_alloc = (PCAPSENDQUEUEALLOC)GetProcAddress(dll, "pcap_sendqueue_alloc");
|
||||
sendqueue_queue = (PCAPSENDQUEUEQUEUE)GetProcAddress(dll, "pcap_sendqueue_queue");
|
||||
sendqueue_destroy = (PCAPSENDQUEUEDESTROY)GetProcAddress(dll, "pcap_sendqueue_destroy");
|
||||
sendqueue_transmit = (PCAPSENDQUEUETRANSMIT)GetProcAddress(dll, "pcap_sendqueue_transmit");
|
||||
datalink = (PCAPDATALINK)GetProcAddress(dll, "pcap_datalink");
|
||||
createsrcstr = (PCAPCREATESRCSTR)GetProcAddress(dll, "pcap_createsrcstr");
|
||||
setbuff = (PCAPSETBUFF)GetProcAddress(dll, "pcap_setbuff");
|
||||
if(findalldevs_ex == NULL || open == NULL ||
|
||||
freealldevs == NULL || close == NULL ||
|
||||
stats == NULL || next_ex == NULL ||
|
||||
sendpacket == NULL ||
|
||||
sendqueue_alloc == NULL ||
|
||||
sendqueue_queue == NULL || sendqueue_destroy == NULL ||
|
||||
sendqueue_transmit == NULL ||
|
||||
datalink == NULL ||
|
||||
createsrcstr == NULL || setbuff == NULL) {
|
||||
closeDLL();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include "icsneo/platform/windows/pcap.h"
|
||||
#include "icsneo/platform/windows/strings.h"
|
||||
#include "icsneo/communication/network.h"
|
||||
#include "icsneo/communication/communication.h"
|
||||
#include "icsneo/communication/ethernetpacketizer.h"
|
||||
#include "icsneo/communication/packetizer.h"
|
||||
#include "icsneo/communication/decoder.h"
|
||||
#include "icsneo/core/ringbuffer.h"
|
||||
#include <pcap.h>
|
||||
#include <iphlpapi.h>
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
|
||||
std::vector<PCAP::NetworkInterface> PCAP::knownInterfaces;
|
||||
|
||||
void PCAP::Find(std::vector<FoundDevice>& found) {
|
||||
const PCAPDLL& pcap = PCAPDLL::getInstance();
|
||||
if(!pcap.ok()) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotStart, APIEvent::Severity::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// First we ask WinPCAP to give us all of the devices
|
||||
pcap_if_t* alldevs;
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = { 0 };
|
||||
bool success = false;
|
||||
// Calling pcap.findalldevs_ex too quickly can cause various errors. Retry a few times in this case.
|
||||
for(auto retry = 0; retry < 10; retry++) {
|
||||
auto ret = pcap.findalldevs_ex((char*)PCAP_SRC_IF_STRING, nullptr, &alldevs, errbuf);
|
||||
if(ret == 0) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!success) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NetworkInterface> interfaces;
|
||||
for(pcap_if_t* dev = alldevs; dev != nullptr; dev = dev->next) {
|
||||
NetworkInterface netif;
|
||||
netif.nameFromWinPCAP = dev->name;
|
||||
netif.descriptionFromWinPCAP = dev->description;
|
||||
interfaces.push_back(netif);
|
||||
}
|
||||
|
||||
pcap.freealldevs(alldevs);
|
||||
|
||||
// Now we're going to ask Win32 for the information as well
|
||||
ULONG size = 0;
|
||||
if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &size) != ERROR_BUFFER_OVERFLOW) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error);
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> adapterAddressBuffer;
|
||||
adapterAddressBuffer.resize(size);
|
||||
if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, (IP_ADAPTER_ADDRESSES*)adapterAddressBuffer.data(), &size) != ERROR_SUCCESS) {
|
||||
EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// aa->AdapterName constains a unique name of the interface like "{3B1D2791-435A-456F-8A7B-9CB0EEE5DAB3}"
|
||||
// iface.nameFromWinPCAP has "rpcap://\Device\NPF_{3B1D2791-435A-456F-8A7B-9CB0EEE5DAB3}"
|
||||
// We're comparing strings to match the Win32 info with the WinPCAP info
|
||||
for(IP_ADAPTER_ADDRESSES* aa = (IP_ADAPTER_ADDRESSES*)adapterAddressBuffer.data(); aa != nullptr; aa = aa->Next) {
|
||||
for(auto& iface : interfaces) {
|
||||
if(iface.nameFromWinPCAP.find(aa->AdapterName) == std::string::npos)
|
||||
continue; // This is not the interface that corresponds
|
||||
|
||||
memcpy(iface.macAddress, aa->PhysicalAddress, sizeof(iface.macAddress));
|
||||
iface.nameFromWin32API = aa->AdapterName;
|
||||
iface.descriptionFromWin32API = convertWideString(aa->Description);
|
||||
iface.friendlyNameFromWin32API = convertWideString(aa->FriendlyName);
|
||||
if(iface.descriptionFromWin32API.find("LAN9512/LAN9514") != std::string::npos) {
|
||||
// This is an Ethernet EVB device
|
||||
iface.fullName = "Intrepid Ethernet EVB ( " + iface.friendlyNameFromWin32API + " : " + iface.descriptionFromWin32API + " )";
|
||||
} else {
|
||||
iface.fullName = iface.friendlyNameFromWin32API + " : " + iface.descriptionFromWin32API;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& iface : interfaces) {
|
||||
bool exists = false;
|
||||
for(auto& known : knownInterfaces)
|
||||
if(memcmp(iface.macAddress, known.macAddress, sizeof(iface.macAddress)) == 0)
|
||||
exists = true;
|
||||
if(!exists)
|
||||
knownInterfaces.emplace_back(iface);
|
||||
}
|
||||
|
||||
constexpr auto openflags = (PCAP_OPENFLAG_MAX_RESPONSIVENESS | PCAP_OPENFLAG_NOCAPTURE_LOCAL);
|
||||
for(size_t i = 0; i < knownInterfaces.size(); i++) {
|
||||
auto& iface = knownInterfaces[i];
|
||||
if(iface.fullName.length() == 0)
|
||||
continue; // Win32 did not find this interface in the previous step
|
||||
|
||||
iface.fp = pcap.open(iface.nameFromWinPCAP.c_str(), 1518, openflags, 1, nullptr, errbuf);
|
||||
|
||||
if(iface.fp == nullptr)
|
||||
continue; // Could not open the interface
|
||||
|
||||
EthernetPacketizer::EthernetPacket requestPacket;
|
||||
memcpy(requestPacket.srcMAC, iface.macAddress, sizeof(requestPacket.srcMAC));
|
||||
requestPacket.payload.reserve(4);
|
||||
requestPacket.payload = {
|
||||
((1 << 4) | (uint8_t)Network::NetID::Main51), // Packet size of 1 on NETID_MAIN51
|
||||
(uint8_t)Command::RequestSerialNumber
|
||||
};
|
||||
requestPacket.payload.push_back(Packetizer::ICSChecksum(requestPacket.payload));
|
||||
requestPacket.payload.insert(requestPacket.payload.begin(), 0xAA);
|
||||
|
||||
auto bs = requestPacket.getBytestream();
|
||||
pcap.sendpacket(iface.fp, bs.data(), (int)bs.size());
|
||||
|
||||
auto timeout = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(250);
|
||||
constexpr const size_t TempBufferSize = 4096;
|
||||
RingBuffer tempBuffer(TempBufferSize);
|
||||
while(std::chrono::high_resolution_clock::now() <= timeout) { // Wait up to 5ms for the response
|
||||
struct pcap_pkthdr* header;
|
||||
const uint8_t* data;
|
||||
auto res = pcap.next_ex(iface.fp, &header, &data);
|
||||
if(res < 0) {
|
||||
//std::cout << "pcapnextex failed with " << res << std::endl;
|
||||
break;
|
||||
}
|
||||
if(res == 0)
|
||||
continue; // Keep waiting for that packet
|
||||
|
||||
EthernetPacketizer ethPacketizer([](APIEvent::Type, APIEvent::Severity) {});
|
||||
memcpy(ethPacketizer.hostMAC, iface.macAddress, sizeof(ethPacketizer.hostMAC));
|
||||
ethPacketizer.allowInPacketsFromAnyMAC = true;
|
||||
if(!ethPacketizer.inputUp({ data, data + header->caplen }))
|
||||
continue; // This packet is not for us
|
||||
|
||||
Packetizer packetizer([](APIEvent::Type, APIEvent::Severity) {});
|
||||
tempBuffer.write(ethPacketizer.outputUp());
|
||||
if(!packetizer.input(tempBuffer))
|
||||
continue; // This packet was not well formed
|
||||
|
||||
EthernetPacketizer::EthernetPacket decoded(data, header->caplen);
|
||||
for(const auto& packet : packetizer.output()) {
|
||||
Decoder decoder([](APIEvent::Type, APIEvent::Severity) {});
|
||||
std::shared_ptr<Message> message;
|
||||
if(!decoder.decode(message, packet))
|
||||
continue;
|
||||
|
||||
const auto serial = std::dynamic_pointer_cast<SerialNumberMessage>(message);
|
||||
if(!serial || serial->deviceSerial.size() != 6)
|
||||
continue;
|
||||
|
||||
FoundDevice foundDevice;
|
||||
foundDevice.handle = (neodevice_handle_t)((i << 24) | (decoded.srcMAC[3] << 16) | (decoded.srcMAC[4] << 8) | (decoded.srcMAC[5]));
|
||||
foundDevice.productId = decoded.srcMAC[2];
|
||||
memcpy(foundDevice.serial, serial->deviceSerial.c_str(), sizeof(foundDevice.serial) - 1);
|
||||
foundDevice.serial[sizeof(foundDevice.serial) - 1] = '\0';
|
||||
|
||||
if(std::any_of(found.begin(), found.end(), [&](const auto& found) { return ::strncmp(foundDevice.serial, found.serial, sizeof(foundDevice.serial)) == 0; }))
|
||||
continue;
|
||||
|
||||
foundDevice.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& device) {
|
||||
return std::unique_ptr<Driver>(new PCAP(reportFn, device));
|
||||
};
|
||||
|
||||
found.push_back(foundDevice);
|
||||
}
|
||||
}
|
||||
|
||||
pcap.close(iface.fp);
|
||||
iface.fp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool PCAP::IsHandleValid(neodevice_handle_t handle) {
|
||||
uint8_t netifIndex = (uint8_t)(handle >> 24);
|
||||
return (netifIndex < knownInterfaces.size());
|
||||
}
|
||||
|
||||
PCAP::PCAP(const device_eventhandler_t& eventHandler, neodevice_t& forDevice) : Driver(eventHandler), pcap(PCAPDLL::getInstance()), device(forDevice), ethPacketizer(eventHandler) {
|
||||
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.
|
||||
|
||||
deviceMAC[0] = 0x00;
|
||||
deviceMAC[1] = 0xFC;
|
||||
deviceMAC[2] = 0x70;
|
||||
deviceMAC[3] = (device.handle >> 16) & 0xFF;
|
||||
deviceMAC[4] = (device.handle >> 8) & 0xFF;
|
||||
deviceMAC[5] = device.handle & 0xFF;
|
||||
memcpy(ethPacketizer.deviceMAC, deviceMAC, 6);
|
||||
memcpy(ethPacketizer.hostMAC, iface.macAddress, 6);
|
||||
} else {
|
||||
openable = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PCAP::open() {
|
||||
if(!openable) {
|
||||
report(APIEvent::Type::InvalidNeoDevice, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pcap.ok()) {
|
||||
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isOpen()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the interface
|
||||
iface.fp = pcap.open(iface.nameFromWinPCAP.c_str(), 65536, PCAP_OPENFLAG_MAX_RESPONSIVENESS | PCAP_OPENFLAG_NOCAPTURE_LOCAL, 50, nullptr, errbuf);
|
||||
if(iface.fp == nullptr) {
|
||||
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create threads
|
||||
readThread = std::thread(&PCAP::readTask, this);
|
||||
writeThread = std::thread(&PCAP::writeTask, this);
|
||||
transmitThread = std::thread(&PCAP::transmitTask, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PCAP::isOpen() {
|
||||
return iface.fp != nullptr;
|
||||
}
|
||||
|
||||
bool PCAP::close() {
|
||||
if(!isOpen()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
setIsClosing(true); // Signal the threads that we are closing
|
||||
readThread.join();
|
||||
writeThread.join();
|
||||
transmitThread.join();
|
||||
setIsClosing(false);
|
||||
|
||||
pcap.close(iface.fp);
|
||||
iface.fp = nullptr;
|
||||
|
||||
clearBuffers();
|
||||
|
||||
transmitQueue = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PCAP::readTask() {
|
||||
struct pcap_pkthdr* header;
|
||||
const uint8_t* data;
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
while(!isClosing()) {
|
||||
auto readBytes = pcap.next_ex(iface.fp, &header, &data);
|
||||
if(readBytes < 0) {
|
||||
report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
|
||||
break;
|
||||
}
|
||||
if(readBytes == 0)
|
||||
continue; // Keep waiting for that packet
|
||||
|
||||
if(ethPacketizer.inputUp({data, data + header->caplen})) {
|
||||
const auto bytes = ethPacketizer.outputUp();
|
||||
pushRx(bytes.data(), bytes.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCAP::writeTask() {
|
||||
WriteOperation writeOp;
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
|
||||
pcap_send_queue* queue1 = pcap.sendqueue_alloc(128000);
|
||||
pcap_send_queue* queue2 = pcap.sendqueue_alloc(128000);
|
||||
pcap_send_queue* queue = queue1;
|
||||
|
||||
while(!isClosing()) {
|
||||
// Potentially, we added frames to a second queue faster than the other thread was able to hand the first
|
||||
// off to the kernel. In that case, wait for a minimal amount of time before checking whether we can
|
||||
// transmit it again.
|
||||
if(writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(queue->len ? 1 : 100))) {
|
||||
unsigned int i = 0;
|
||||
do {
|
||||
ethPacketizer.inputDown(std::move(writeOp.bytes));
|
||||
if(i++ >= (queue->maxlen - queue->len) / 1518 / 3)
|
||||
break; // Not safe to try to fit any more packets in this queue, let it transmit and come around again
|
||||
} while(writeQueue.try_dequeue(writeOp));
|
||||
|
||||
for(const auto& data : ethPacketizer.outputDown()) {
|
||||
pcap_pkthdr header = {};
|
||||
header.caplen = header.len = bpf_u_int32(data.size());
|
||||
if(pcap.sendqueue_queue(queue, &header, data.data()) != 0)
|
||||
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventWarning);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lk(transmitQueueMutex);
|
||||
// Check if we want to transmit our current queue
|
||||
// If we're not currently transmitting a queue, let this one transmit immediately for good latency
|
||||
// If our queue is full and we're transmitting the other, we can't accept any more packets out of the writeQueue
|
||||
// In that case we're putting as many packets into the driver as possible, so wait for it to be free
|
||||
// This puts the backpressure on the writeQueue
|
||||
if(queue->len && (!transmitQueue || queue->len + (1518*2) >= queue->maxlen)) {
|
||||
if(transmitQueue) // Need to wait for the queue to become available
|
||||
transmitQueueCV.wait(lk, [this] { return !transmitQueue; });
|
||||
|
||||
// Time to swap
|
||||
transmitQueue = queue;
|
||||
lk.unlock();
|
||||
transmitQueueCV.notify_one();
|
||||
|
||||
// Set up our next queue
|
||||
if(queue == queue1) {
|
||||
pcap.sendqueue_destroy(queue2);
|
||||
queue = queue2 = pcap.sendqueue_alloc(128000);
|
||||
} else {
|
||||
pcap.sendqueue_destroy(queue1);
|
||||
queue = queue1 = pcap.sendqueue_alloc(128000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pcap.sendqueue_destroy(queue1);
|
||||
pcap.sendqueue_destroy(queue2);
|
||||
}
|
||||
|
||||
void PCAP::transmitTask() {
|
||||
while(!isClosing()) {
|
||||
std::unique_lock<std::mutex> lk(transmitQueueMutex);
|
||||
if(transmitQueueCV.wait_for(lk, std::chrono::milliseconds(100), [this] { return !!transmitQueue; }) && !isClosing() && transmitQueue) {
|
||||
pcap_send_queue* current = transmitQueue;
|
||||
lk.unlock();
|
||||
pcap.sendqueue_transmit(iface.fp, current, 0);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk2(transmitQueueMutex);
|
||||
transmitQueue = nullptr;
|
||||
}
|
||||
transmitQueueCV.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "icsneo/platform/windows/registry.h"
|
||||
#include "icsneo/platform/windows/strings.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#include <vector>
|
||||
#include <locale>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
class Key {
|
||||
public:
|
||||
Key(std::wstring path, bool readwrite = false);
|
||||
~Key();
|
||||
HKEY GetKey() { return key; }
|
||||
bool IsOpen() { return key != nullptr; }
|
||||
private:
|
||||
HKEY key;
|
||||
};
|
||||
|
||||
Key::Key(std::wstring path, bool readwrite) {
|
||||
DWORD dwDisposition;
|
||||
if(readwrite)
|
||||
RegCreateKeyExW(HKEY_LOCAL_MACHINE, path.c_str(), 0, nullptr, 0, KEY_QUERY_VALUE | KEY_WRITE, nullptr, &key, &dwDisposition);
|
||||
else
|
||||
RegOpenKeyExW(HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_READ, &key);
|
||||
}
|
||||
|
||||
Key::~Key() {
|
||||
if(IsOpen())
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
bool Registry::EnumerateSubkeys(std::wstring path, std::vector<std::wstring>& subkeys) {
|
||||
Key regKey(path);
|
||||
if(!regKey.IsOpen())
|
||||
return false;
|
||||
|
||||
wchar_t className[MAX_PATH];
|
||||
memset(className, 0, sizeof(className));
|
||||
DWORD classNameLen = MAX_PATH;
|
||||
DWORD subKeyCount = 0;
|
||||
DWORD maxSubKeyLen, maxClassStringLen, valueCount, maxValueNameLen, maxValueDataLen, securityDescriptorLen;
|
||||
FILETIME lastWriteTime;
|
||||
auto ret = RegQueryInfoKeyW(
|
||||
regKey.GetKey(),
|
||||
className,
|
||||
&classNameLen,
|
||||
nullptr,
|
||||
&subKeyCount,
|
||||
&maxSubKeyLen,
|
||||
&maxClassStringLen,
|
||||
&valueCount,
|
||||
&maxValueNameLen,
|
||||
&maxValueDataLen,
|
||||
&securityDescriptorLen,
|
||||
&lastWriteTime);
|
||||
|
||||
if(ret != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
subkeys.clear();
|
||||
for(DWORD i = 0; i < subKeyCount; i++) {
|
||||
DWORD nameLen = MAX_PATH;
|
||||
wchar_t name[MAX_PATH];
|
||||
memset(name, 0, sizeof(name));
|
||||
ret = RegEnumKeyExW(regKey.GetKey(), i, name, &nameLen, nullptr, nullptr, nullptr, &lastWriteTime);
|
||||
if(ret == ERROR_SUCCESS)
|
||||
subkeys.push_back(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Registry::Get(std::wstring path, std::wstring key, std::wstring& value) {
|
||||
Key regKey(path);
|
||||
if(!regKey.IsOpen())
|
||||
return false;
|
||||
|
||||
// Query for the type and size of the data
|
||||
DWORD type, size;
|
||||
auto ret = RegQueryValueExW(regKey.GetKey(), key.c_str(), nullptr, &type, (LPBYTE)nullptr, &size);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
// Query for the data itself
|
||||
std::vector<wchar_t> data(size / 2 + 1);
|
||||
DWORD bytesRead = size; // We want to read up to the size we got earlier
|
||||
ret = RegQueryValueExW(regKey.GetKey(), key.c_str(), nullptr, &type, (LPBYTE)data.data(), &bytesRead);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
value = data.data();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Registry::Get(std::string path, std::string key, std::string& value) {
|
||||
std::wstring wvalue;
|
||||
bool ret = Get(convertStringToWide(path), convertStringToWide(key), wvalue);
|
||||
value = convertWideString(wvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Registry::Get(std::wstring path, std::wstring key, uint32_t& value) {
|
||||
Key regKey(path);
|
||||
if(!regKey.IsOpen())
|
||||
return false;
|
||||
|
||||
// Query for the data
|
||||
DWORD type, size = sizeof(DWORD), kvalue;
|
||||
auto ret = RegQueryValueExW(regKey.GetKey(), key.c_str(), nullptr, &type, (LPBYTE)&kvalue, &size);
|
||||
if(ret != ERROR_SUCCESS || type != REG_DWORD)
|
||||
return false;
|
||||
|
||||
value = kvalue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Registry::Get(std::string path, std::string key, uint32_t& value) {
|
||||
return Get(convertStringToWide(path), convertStringToWide(key), value);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
#include <icsneo/platform/windows/strings.h>
|
||||
|
||||
// Helper function to convert UTF-16 to UTF-8 strings (wide to standard)
|
||||
std::string icsneo::convertWideString(const std::wstring& value) {
|
||||
// Get the width of the string (character count)
|
||||
int width = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)value.c_str(), -1, 0, 0, NULL, NULL);
|
||||
// Create the new string
|
||||
std::string new_string(width+1, '\0');
|
||||
// fill the new string with the converted characters
|
||||
WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)value.c_str(), -1, new_string.data(), width, NULL, NULL);
|
||||
return new_string;
|
||||
};
|
||||
|
||||
// Helper function to convert UTF-8 to UTF-16 strings (standard to wide)
|
||||
std::wstring icsneo::convertStringToWide(const std::string& value) {
|
||||
// Get the width of the string (character count)
|
||||
int width = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, NULL, 0);
|
||||
// Create the new string
|
||||
std::wstring new_string(width+1, '\0');
|
||||
// fill the new string with the converted characters
|
||||
MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, (LPWSTR)new_string.data(), width);
|
||||
return new_string;
|
||||
}
|
||||
Reference in New Issue
Block a user