diff --git a/CMakeLists.txt b/CMakeLists.txt index 90da4e0..d0a6fc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,6 +240,8 @@ set(SRC_FILES communication/packet/i2cpacket.cpp communication/packet/linpacket.cpp communication/packet/scriptstatuspacket.cpp + communication/packet/componentversionpacket.cpp + communication/packet/supportedfeaturespacket.cpp communication/decoder.cpp communication/encoder.cpp communication/ethernetpacketizer.cpp diff --git a/api/icsneocpp/event.cpp b/api/icsneocpp/event.cpp index d817013..11aec0b 100644 --- a/api/icsneocpp/event.cpp +++ b/api/icsneocpp/event.cpp @@ -115,6 +115,7 @@ static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI up static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream."; static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same."; static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected."; +static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device."; // Transport Errors static constexpr const char* FAILED_TO_READ = "A read operation failed."; @@ -290,6 +291,8 @@ const char* APIEvent::DescriptionForType(Type type) { return COREMINI_UPLOAD_VERSION_MISMATCH; case Type::DiskNotConnected: return DISK_NOT_CONNECTED; + case Type::UnexpectedResponse: + return UNEXPECTED_RESPONSE; // Transport Errors case Type::FailedToRead: return FAILED_TO_READ; diff --git a/communication/communication.cpp b/communication/communication.cpp index fb33744..9b18d6a 100644 --- a/communication/communication.cpp +++ b/communication/communication.cpp @@ -13,6 +13,7 @@ #include "icsneo/communication/message/filter/main51messagefilter.h" #include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/versionmessage.h" +#include "icsneo/communication/message/componentversionsmessage.h" using namespace icsneo; @@ -301,3 +302,18 @@ void Communication::handleInput(Packetizer& p, std::vector& readBytes) } } } + +std::optional< std::vector > Communication::getComponentVersionsSync(std::chrono::milliseconds timeout) { + static const std::shared_ptr filter = std::make_shared(Message::Type::ComponentVersions); + std::shared_ptr msg = waitForMessageSync([this]() { + return sendCommand(ExtendedCommand::GetComponentVersions, {}); + }, filter, timeout); + if(!msg) // Did not receive a message + return std::nullopt; + + auto ver = std::dynamic_pointer_cast(msg); + if(!ver) // Could not upcast for some reason + return std::nullopt; + + return std::make_optional< std::vector >(std::move(ver->versions)); +} diff --git a/communication/decoder.cpp b/communication/decoder.cpp index 16eaa52..2df65e3 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -26,6 +26,8 @@ #include "icsneo/communication/packet/i2cpacket.h" #include "icsneo/communication/packet/scriptstatuspacket.h" #include "icsneo/communication/packet/linpacket.h" +#include "icsneo/communication/packet/componentversionpacket.h" +#include "icsneo/communication/packet/supportedfeaturespacket.h" #include using namespace icsneo; @@ -247,13 +249,21 @@ bool Decoder::decode(std::shared_ptr& result, const std::shared_ptr(packet->data.data()); - if(resp.header.command != ExtendedCommand::GenericReturn) - break; // Handle as a raw message - - const auto msg = std::make_shared(resp.command, resp.returnCode); - result = msg; - return true; - } + switch(resp.header.command) { + case ExtendedCommand::GetComponentVersions: + result = ComponentVersionPacket::DecodeToMessage(packet->data); + return true; + case ExtendedCommand::GetSupportedFeatures: + result = SupportedFeaturesPacket::DecodeToMessage(packet->data); + return true; + case ExtendedCommand::GenericReturn: + result = std::make_shared(resp.command, resp.returnCode); + return true; + default: + // No defined handler, treat this as a RawMessage + break; + } + } break; case Network::NetID::FlexRayControl: { auto frResult = std::make_shared(*packet); if(!frResult->decoded) { diff --git a/communication/packet/componentversionpacket.cpp b/communication/packet/componentversionpacket.cpp new file mode 100644 index 0000000..ab29985 --- /dev/null +++ b/communication/packet/componentversionpacket.cpp @@ -0,0 +1,45 @@ +#include "icsneo/communication/packet/componentversionpacket.h" +#include "icsneo/communication/message/componentversionsmessage.h" + +using namespace icsneo; + +#pragma pack(push, 2) +struct PackedComponentVersion { + uint8_t valid; + uint8_t expansionSlot; + uint8_t componentInfo; // Component specific data (e.g. Linux: boot device) + uint8_t reserved; + uint32_t identifier; + uint32_t dotVersion; // Represents a.b.c.d, a.b.c, or a.b, depending on leading zeros. + uint32_t commitHash; +}; + +static constexpr size_t MaxReportedVersions = 16; +struct ComponentVersionsResponse { + ExtendedResponseMessage::ResponseHeader header; + uint16_t numVersions; + PackedComponentVersion versions[MaxReportedVersions]; +}; +#pragma pack(pop) + +std::shared_ptr ComponentVersionPacket::DecodeToMessage(const std::vector& bytes) { + auto msg = std::make_shared(); + // Length checks: At least a header and numVersions field. + if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 2) { + return msg; // Empty + } + // Get a reference to the payload to fully validate the length + const auto& response = *reinterpret_cast(bytes.data()); + // Expected size is the header, numVersions field, and numVersions ComponentVersion objects. + auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 2 + (response.numVersions * sizeof(ComponentVersion)); + // If the response is malformed (too small), return an empty message. + if(bytes.size() < expectedSize) { + return msg; // Empty + } + // Unpack into the portable class + for(unsigned int i = 0; i < response.numVersions; ++i) { + const auto& packedVersion = response.versions[i]; + msg->versions.emplace_back(packedVersion.valid, packedVersion.componentInfo, packedVersion.identifier, packedVersion.dotVersion, packedVersion.commitHash); + } + return msg; +} diff --git a/communication/packet/supportedfeaturespacket.cpp b/communication/packet/supportedfeaturespacket.cpp new file mode 100644 index 0000000..b317ce5 --- /dev/null +++ b/communication/packet/supportedfeaturespacket.cpp @@ -0,0 +1,41 @@ +#include "icsneo/communication/packet/supportedfeaturespacket.h" +#include "icsneo/communication/message/supportedfeaturesmessage.h" + +using namespace icsneo; + +static constexpr uint16_t SupportedFeaturesCommandVersion = 1; +static constexpr size_t NumSupportedFeaturesFields = + (static_cast(SupportedFeature::numSupportedFeatures) + 31) / 32; +#pragma pack(push, 2) +struct SupportedFeaturesResponse { + ExtendedResponseMessage::ResponseHeader header; + uint16_t cmdVersion; + uint16_t numValidBits; + uint32_t featuresFields[NumSupportedFeaturesFields]; +}; +#pragma pack(pop) + +std::shared_ptr SupportedFeaturesPacket::DecodeToMessage(const std::vector& bytes) { + auto msg = std::make_shared(); + // Length check: At least a header, a 2-byte cmdVersion field, and a 2-byte numValidBits field. + if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 4) { + return msg; // Empty + } + // Get a reference to the payload to fully validate the length + const auto& response = *reinterpret_cast(bytes.data()); + // Expected size is the header, cmdVersion and numValidBits fields, plus the number of 32-bit bitfields in the response based on numValidBits + auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 4 + ((response.numValidBits + 31) / 32) * 4; + // If the response is malformed (too small), return an empty message + if(bytes.size() < expectedSize) { + return msg; // Empty + } + unsigned int loopLimit = std::min(response.numValidBits, NumSupportedFeaturesFields); + for(unsigned int i = 0; i < loopLimit; ++i) { + uint32_t wordOffset = i / 32; + uint32_t bitOffset = i % 32; + if((response.featuresFields[wordOffset] >> bitOffset) & 1) { + msg->features.insert(static_cast(i)); + } + } + return msg; +} diff --git a/device/device.cpp b/device/device.cpp index 6a731d8..e1db9fb 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -217,6 +217,13 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) { if(block) // Extensions say no return false; + // Get component versions *after* the extension "onDeviceOpen" hooks (e.g. device reflashes) + + if (auto compVersions = com->getComponentVersionsSync()) + componentVersions = std::move(*compVersions); + else + report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::EventWarning); + if(!settings->disabled) { // Since we will not fail the open if a settings read fails, // downgrade any errors to warnings. Otherwise the error will @@ -303,6 +310,10 @@ APIEvent::Type Device::attemptToBeginCommunication() { return getCommunicationNotEstablishedError(); } + if(!com->sendCommand(Command::EnableNetworkCommunication, false)) + return getCommunicationNotEstablishedError(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + auto serial = com->getSerialNumberSync(); int i = 0; while(!serial) { @@ -1751,4 +1762,21 @@ bool Device::setRTC(const std::chrono::time_point& ti com->sendCommand(Command::SetRTC, bytestream); return true; -} \ No newline at end of file +} + +std::optional> Device::getSupportedFeatures() { + auto timeout = std::chrono::milliseconds(100); + std::shared_ptr msg = com->waitForMessageSync( + [this](){ return com->sendCommand(ExtendedCommand::GetSupportedFeatures, {}); }, + std::make_shared(Message::Type::SupportedFeatures), timeout); + if(!msg) { + report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error); + return std::nullopt; + } + const auto& typedResponse = std::dynamic_pointer_cast(msg); + if(!typedResponse) { + report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error); + return std::nullopt; + } + return std::move(typedResponse->features); +} diff --git a/include/icsneo/api/event.h b/include/icsneo/api/event.h index 968dfd3..4fcc282 100644 --- a/include/icsneo/api/event.h +++ b/include/icsneo/api/event.h @@ -93,6 +93,7 @@ public: A2BMessageIncompleteFrame = 0x2039, CoreminiUploadVersionMismatch = 0x2040, DiskNotConnected = 0x2041, + UnexpectedResponse = 0x2042, // Transport Events FailedToRead = 0x3000, diff --git a/include/icsneo/communication/command.h b/include/icsneo/communication/command.h index c36ae06..c1ac504 100644 --- a/include/icsneo/communication/command.h +++ b/include/icsneo/communication/command.h @@ -47,6 +47,8 @@ enum class ExtendedCommand : uint16_t { Extract = 0x0015, StartDHCPServer = 0x0016, StopDHCPServer = 0x0017, + GetSupportedFeatures = 0x0018, + GetComponentVersions = 0x001A, Reboot = 0x001C, SetUploadedFlag = 0x0027, }; diff --git a/include/icsneo/communication/communication.h b/include/icsneo/communication/communication.h index 87ab9b6..65e1d5d 100644 --- a/include/icsneo/communication/communication.h +++ b/include/icsneo/communication/communication.h @@ -10,6 +10,8 @@ #include "icsneo/communication/message/callback/messagecallback.h" #include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/logicaldiskinfomessage.h" +#include "icsneo/communication/message/componentversionsmessage.h" +#include "icsneo/communication/message/extendedresponsemessage.h" #include "icsneo/device/deviceversion.h" #include "icsneo/api/eventmanager.h" #include "icsneo/communication/packetizer.h" @@ -58,6 +60,7 @@ public: std::shared_ptr getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::optional< std::vector< std::optional > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); + std::optional< std::vector > getComponentVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); int addMessageCallback(const std::shared_ptr& cb); bool removeMessageCallback(int id); diff --git a/include/icsneo/communication/message/componentversionsmessage.h b/include/icsneo/communication/message/componentversionsmessage.h new file mode 100644 index 0000000..fc39233 --- /dev/null +++ b/include/icsneo/communication/message/componentversionsmessage.h @@ -0,0 +1,29 @@ +#ifndef _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_ +#define _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_ + +#ifdef __cplusplus +#include "icsneo/communication/message/extendedresponsemessage.h" + +namespace icsneo { +class ComponentVersion { +public: + ComponentVersion(uint8_t valid, uint8_t componentInfo, uint32_t identifier, uint32_t dotVersion, uint32_t commitHash) : + valid(valid), componentInfo(componentInfo), identifier(identifier), dotVersion(dotVersion), commitHash(commitHash) {} + const bool valid; + const uint8_t componentInfo; + const uint32_t identifier; + const uint32_t dotVersion; + const uint32_t commitHash; +}; + +class ComponentVersionsMessage : public Message { +public: + ComponentVersionsMessage() : Message(Message::Type::ComponentVersions) {} + std::vector versions; +}; + +} + +#endif // __cplusplus + +#endif // _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_ \ No newline at end of file diff --git a/include/icsneo/communication/message/message.h b/include/icsneo/communication/message/message.h index 8bb16a8..d803465 100644 --- a/include/icsneo/communication/message/message.h +++ b/include/icsneo/communication/message/message.h @@ -34,6 +34,8 @@ public: ExtendedResponse = 0x8009, WiVICommandResponse = 0x800a, ScriptStatus = 0x800b, + ComponentVersions = 0x800c, + SupportedFeatures = 0x800d, }; Message(Type t) : type(t) {} diff --git a/include/icsneo/communication/message/supportedfeaturesmessage.h b/include/icsneo/communication/message/supportedfeaturesmessage.h new file mode 100644 index 0000000..6633408 --- /dev/null +++ b/include/icsneo/communication/message/supportedfeaturesmessage.h @@ -0,0 +1,44 @@ +#ifndef _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_ +#define _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_ + +#ifdef __cplusplus +#include "icsneo/communication/message/extendedresponsemessage.h" +#include +#include + +namespace icsneo { + +enum class SupportedFeature : uint16_t { + networkDWCAN01 = 0, + networkDWCAN02 = 1, + networkDWCAN03 = 2, + networkDWCAN04 = 3, + networkDWCAN05 = 4, + networkDWCAN06 = 5, + networkDWCAN07 = 6, + networkDWCAN08 = 7, + networkTerminationDWCAN01 = 8, + networkTerminationDWCAN02 = 9, + networkTerminationDWCAN03 = 10, + networkTerminationDWCAN04 = 11, + networkTerminationDWCAN05 = 12, + networkTerminationDWCAN06 = 13, + networkTerminationDWCAN07 = 14, + networkTerminationDWCAN08 = 15, + enhancedFlashDriver = 16, + rtcCalibration = 17, + rtcClosedLoopCalibration = 18, + numSupportedFeatures, +}; + +class SupportedFeaturesMessage : public Message { +public: + SupportedFeaturesMessage() : Message(Message::Type::SupportedFeatures) {} + std::set features; +}; + +} + +#endif // __cplusplus + +#endif // _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_ \ No newline at end of file diff --git a/include/icsneo/communication/packet/componentversionpacket.h b/include/icsneo/communication/packet/componentversionpacket.h new file mode 100644 index 0000000..16f6a4a --- /dev/null +++ b/include/icsneo/communication/packet/componentversionpacket.h @@ -0,0 +1,22 @@ +#ifndef __COMPONENTVERSIONPACKET_H__ +#define __COMPONENTVERSIONPACKET_H__ + +#ifdef __cplusplus + +#include +#include +#include + +namespace icsneo { + +class ComponentVersionsMessage; + +struct ComponentVersionPacket { + static std::shared_ptr DecodeToMessage(const std::vector& bytes); +}; + +} + +#endif // __cplusplus + +#endif // __DEVICECOMPONENTVERSIONPACKET_H__ diff --git a/include/icsneo/communication/packet/supportedfeaturespacket.h b/include/icsneo/communication/packet/supportedfeaturespacket.h new file mode 100644 index 0000000..5c42d9e --- /dev/null +++ b/include/icsneo/communication/packet/supportedfeaturespacket.h @@ -0,0 +1,22 @@ +#ifndef __SUPPORTEDFEATURESPACKET_H_ +#define __SUPPORTEDFEATURESPACKET_H_ + +#ifdef __cplusplus + +#include +#include +#include + +namespace icsneo { + +class SupportedFeaturesMessage; + +struct SupportedFeaturesPacket { + static std::shared_ptr DecodeToMessage(const std::vector& bytes); +}; + +} + +#endif // __cplusplus + +#endif // __SUPPORTEDFEATURESPACKET_H_ diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index ab706ca..39cc34e 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "icsneo/api/eventmanager.h" #include "icsneo/api/lifetime.h" #include "icsneo/device/neodevice.h" @@ -31,6 +32,7 @@ #include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/wiviresponsemessage.h" #include "icsneo/communication/message/scriptstatusmessage.h" +#include "icsneo/communication/message/supportedfeaturesmessage.h" #include "icsneo/device/extensions/flexray/controller.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/communication/message/ethphymessage.h" @@ -530,7 +532,7 @@ public: * For use by extensions only. A more stable API will be provided in the future. */ const std::vector>& getVersions() const { return versions; } - + const std::vector& getComponentVersions() const { return componentVersions; } /** * Some alternate communication protocols do not support DFU */ @@ -548,6 +550,9 @@ public: std::optional> getRTC(); bool setRTC(const std::chrono::time_point& time); + // Get a bitfield from the device representing supported networks and features. + std::optional> getSupportedFeatures(); + /** * Returns true if this device supports the Wireless neoVI featureset */ @@ -669,6 +674,7 @@ private: neodevice_t data; std::shared_ptr latestResetStatus; std::vector> versions; + std::vector componentVersions; mutable std::mutex diskLock; std::unique_ptr diskReadDriver; diff --git a/include/icsneo/device/tree/neovifire3/neovifire3.h b/include/icsneo/device/tree/neovifire3/neovifire3.h index 433a8ce..211f90a 100644 --- a/include/icsneo/device/tree/neovifire3/neovifire3.h +++ b/include/icsneo/device/tree/neovifire3/neovifire3.h @@ -62,7 +62,7 @@ protected: void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); - packetizer.align16bit = false; + packetizer.align16bit = true; } void setupSupportedRXNetworks(std::vector& rxNetworks) override { diff --git a/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h b/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h index e8eecb7..3cfb1de 100644 --- a/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h +++ b/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h @@ -64,7 +64,7 @@ protected: void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); - packetizer.align16bit = false; + packetizer.align16bit = true; } void setupSupportedRXNetworks(std::vector& rxNetworks) override { diff --git a/include/icsneo/device/tree/neovired2/neovired2.h b/include/icsneo/device/tree/neovired2/neovired2.h index 51fe687..ee7d0e0 100644 --- a/include/icsneo/device/tree/neovired2/neovired2.h +++ b/include/icsneo/device/tree/neovired2/neovired2.h @@ -47,7 +47,7 @@ protected: void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); - packetizer.align16bit = false; + packetizer.align16bit = true; } void setupSupportedRXNetworks(std::vector& rxNetworks) override { diff --git a/include/icsneo/platform/tcp.h b/include/icsneo/platform/tcp.h index 8b0c2a5..2ebab9e 100644 --- a/include/icsneo/platform/tcp.h +++ b/include/icsneo/platform/tcp.h @@ -3,7 +3,7 @@ #ifdef __cplusplus -#include +#include #include "icsneo/communication/driver.h" #include "icsneo/device/founddevice.h" @@ -45,7 +45,7 @@ private: NetworkInterface interface; uint32_t dstIP; uint16_t dstPort; - std::optional socket; + std::unique_ptr socket; void readTask() override; void writeTask() override; }; diff --git a/platform/posix/cdcacm.cpp b/platform/posix/cdcacm.cpp index 5cecfea..0cf7bed 100644 --- a/platform/posix/cdcacm.cpp +++ b/platform/posix/cdcacm.cpp @@ -198,7 +198,7 @@ void CDCACM::readTask() { // We were expecting a disconnect for reenumeration modeChangeThread = std::thread([this] { modeChangeCV.notify_all(); - close(); // Which will trigger an open() due to modeChanging + // Requesting thread is responsible for calling close. This allows for more flexibility }); break; } else if(!closing && !fdIsValid() && !isDisconnected()) { diff --git a/platform/tcp.cpp b/platform/tcp.cpp index 53b146c..6c513a7 100644 --- a/platform/tcp.cpp +++ b/platform/tcp.cpp @@ -16,6 +16,7 @@ #include #endif +#include #include "icsneo/platform/tcp.h" #ifdef _WIN32 @@ -415,9 +416,10 @@ bool TCP::open() { return false; } - socket.emplace(AF_INET, SOCK_STREAM, IPPROTO_TCP); + auto partiallyOpenSocket = std::make_unique(AF_INET, SOCK_STREAM, IPPROTO_TCP); + #if !defined(_WIN32) && !defined(__APPLE__) - if(::setsockopt(*socket, SOL_SOCKET, SO_BINDTODEVICE, interface.name.c_str(), interface.name.size()) < 0) { + if(::setsockopt(*partiallyOpenSocket, SOL_SOCKET, SO_BINDTODEVICE, interface.name.c_str(), interface.name.size()) < 0) { report(APIEvent::Type::ErrorSettingSocketOption, APIEvent::Severity::Error); return false; } @@ -428,7 +430,7 @@ bool TCP::open() { addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(interface.ip); APPLE_SIN_LEN(addr); - if(::bind(*socket, (sockaddr*)&addr, sizeof(addr)) < 0) { + if(::bind(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) < 0) { report(APIEvent::Type::FailedToBind, APIEvent::Severity::Error); return false; } @@ -442,7 +444,7 @@ bool TCP::open() { APPLE_SIN_LEN(addr); // the socket is non-blocking so it's expected that the first connect will fail - if(::connect(*socket, (sockaddr*)&addr, sizeof(addr)) == 0) { + if(::connect(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) == 0) { report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error); return false; } @@ -462,11 +464,11 @@ bool TCP::open() { timeout.tv_sec = 1; fd_set writefs; FD_ZERO(&writefs); - int nfds = WIN_INT(*socket) + 1; - FD_SET(*socket, &writefs); + int nfds = WIN_INT(*partiallyOpenSocket) + 1; + FD_SET(*partiallyOpenSocket, &writefs); ::select(nfds, 0, &writefs, 0, &timeout); - if(::connect(*socket, (sockaddr*)&addr, sizeof(addr)) < 0) { + if(::connect(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) < 0) { #ifdef _WIN32 if(::WSAGetLastError() != WSAEISCONN) { report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error); @@ -484,13 +486,14 @@ bool TCP::open() { } } + socket = std::move(partiallyOpenSocket); readThread = std::thread(&TCP::readTask, this); writeThread = std::thread(&TCP::writeTask, this); return true; } bool TCP::isOpen() { - return socket.has_value(); + return socket ? true : false; } bool TCP::close() { @@ -513,6 +516,7 @@ bool TCP::close() { while(writeQueue.try_dequeue(flushop)) {} socket.reset(); + closing = false; return true; }