diff --git a/CMakeLists.txt b/CMakeLists.txt index 697786a..850c790 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,10 @@ include_directories( ) # Find core dependencies -find_package(Boost 1.69.0 REQUIRED COMPONENTS system) +# Boost 1.72.0 is required to ensure that a certain bug where boost::asio +# objects depend on specific copies of symbols, and boost will cause a segfault +# if boost::asio objects are used inside of a dlopen()'d library, is fixed. +find_package(Boost 1.73.0 REQUIRED COMPONENTS system) find_package(PkgConfig REQUIRED) find_package(FLEX REQUIRED) find_package(BISON REQUIRED) diff --git a/commonLibs/livoxProto1/device.cpp b/commonLibs/livoxProto1/device.cpp index b5014fb..11ddaa9 100644 --- a/commonLibs/livoxProto1/device.cpp +++ b/commonLibs/livoxProto1/device.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include "device.h" @@ -77,6 +79,7 @@ componentThread(componentThread), handshakeTimeoutMs(handshakeTimeoutMs), retryDelayMs(retryDelayMs), smoIp(smoIp), smoSubnetNbits(smoSubnetNbits), dataPort(dataPort), cmdPort(cmdPort), imuPort(imuPort), +heartbeatSocketFd(-1), heartbeatActive(false) { connect(); @@ -92,7 +95,10 @@ Device::~Device() } heartbeatTimer.reset(); - heartbeatSocket.reset(); + if (heartbeatSocketFd >= 0) { + close(heartbeatSocketFd); + heartbeatSocketFd = -1; + } } void Device::connect() @@ -426,20 +432,36 @@ void Device::startHeartbeat() } /** EXPLANATION: - * Create heartbeat socket using io_service of the componentThread that was - * given to us for use by this device. + * Create raw UDP socket for heartbeat sending to avoid boost::asio dlopen + * issues. */ - heartbeatSocket = std::make_unique( - componentThread->getIoService()); - heartbeatSocket->open(boost::asio::ip::udp::v4()); + heartbeatSocketFd = socket(AF_INET, SOCK_DGRAM, 0); + if (heartbeatSocketFd < 0) + { + std::cerr << "[" << __func__ << "] Failed to create heartbeat socket: " + << strerror(errno) << std::endl; + return; + } /** EXPLANATION: * Bind heartbeat socket to cmdPort so heartbeats come from the same port * as handshake. */ - boost::asio::ip::udp::endpoint heartbeatLocalEndpoint( - boost::asio::ip::address_v4::any(), cmdPort); - heartbeatSocket->bind(heartbeatLocalEndpoint); + struct sockaddr_in localAddr; + memset(&localAddr, 0, sizeof(localAddr)); + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = INADDR_ANY; + localAddr.sin_port = htons(cmdPort); + + if (bind( + heartbeatSocketFd, (struct sockaddr*)&localAddr, sizeof(localAddr)) < 0) + { + std::cerr << "[" << __func__ << "] Failed to bind heartbeat socket to " + "port " << cmdPort << ": " << strerror(errno) << std::endl; + close(heartbeatSocketFd); + heartbeatSocketFd = -1; + return; + } // Create heartbeat timer heartbeatTimer = std::make_unique( @@ -453,7 +475,7 @@ void Device::startHeartbeat() void Device::sendHeartbeat() { - if (!heartbeatActive.load() || !heartbeatSocket + if (!heartbeatActive.load() || heartbeatSocketFd < 0 || discoveredDevice.ipAddr.empty()) { return; @@ -468,13 +490,24 @@ void Device::sendHeartbeat() heartbeatMsg.footer.crc_32 = heartbeatMsg.calculateCrc32(); heartbeatMsg.footer.swapCrc32ToProtocolEndianness(); - boost::asio::ip::udp::endpoint deviceEndpoint( - boost::asio::ip::address::from_string(discoveredDevice.ipAddr), - 65000); // Heartbeats and commands go to port 65000 + // Set up destination address for raw socket + struct sockaddr_in deviceAddr; + memset(&deviceAddr, 0, sizeof(deviceAddr)); + deviceAddr.sin_family = AF_INET; + deviceAddr.sin_addr.s_addr = inet_addr(discoveredDevice.ipAddr.c_str()); + // Heartbeats and commands go to port 65000 + deviceAddr.sin_port = htons(65000); - heartbeatSocket->send_to( - boost::asio::buffer(&heartbeatMsg, sizeof(heartbeatMsg)), - deviceEndpoint); + ssize_t bytesSent = sendto( + heartbeatSocketFd, &heartbeatMsg, sizeof(heartbeatMsg), 0, + (struct sockaddr*)&deviceAddr, sizeof(deviceAddr)); + + if (bytesSent < 0) + { + std::cerr << "[" << __func__ << "] Failed to send heartbeat: " + << strerror(errno) << std::endl; + return; + } /** EXPLANATION: * Schedule next heartbeat in 1 second, per the spec. diff --git a/commonLibs/livoxProto1/device.h b/commonLibs/livoxProto1/device.h index 694aaae..db1658e 100644 --- a/commonLibs/livoxProto1/device.h +++ b/commonLibs/livoxProto1/device.h @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include #include "protocol.h" @@ -94,7 +98,7 @@ private: // Heartbeat state std::unique_ptr heartbeatTimer; - std::unique_ptr heartbeatSocket; + int heartbeatSocketFd; // Raw socket file descriptor std::atomic heartbeatActive; };