livoxProto1: detectSmoIp should be based on target dev IP

We previously used the smoIp provided by the user, but this
function is intended to enable us to figure out the correct
IP to send to the target device in the Handshake message.
This commit is contained in:
2025-09-06 20:44:28 -04:00
parent a0d577bf81
commit d2bf5aceee
2 changed files with 35 additions and 24 deletions
+33 -22
View File
@@ -204,7 +204,9 @@ bool Device::executeHandshake(
boost::asio::ip::udp::socket socket(io_context);
socket.open(boost::asio::ip::udp::v4());
std::string smoIp = getSmoIp();
// Get the IP addr of the SMO machine's iface that is facing the device.
std::string smoIp = getSmoIp(deviceIP);
comms::HandshakeRequest handshakeReq(smoIp, dataPort, cmdPort, imuPort);
handshakeReq.swapContentsToProtocolEndianness();
handshakeReq.header.setCrc16FromRawBytes();
@@ -501,33 +503,40 @@ uint32_t Device::getSubnetMaskFor(uint8_t nbits)
}
}
std::optional<std::string> Device::detectSmoIp()
std::optional<std::string> Device::detectSmoIp(const std::string& deviceIP)
{
/** EXPLANATION:
* This function detects the SMO IP address of the interface that's facing
* the device by iterating through all network interfaces and checking for
* the interface that has the IP address in the same subnet as the device's
* IP address.
*/
try {
// Parse the smoIp to get the network prefix
auto smoIpOctets = comms::parseIPv4Address(smoIp);
if (!smoIpOctets.has_value()) {
// Parse the device IP to get the network prefix
auto deviceIpOctets = comms::parseIPv4Address(deviceIP);
if (!deviceIpOctets.has_value()) {
return std::nullopt;
}
// Convert smoIp octets to integers for bitwise operations
uint32_t smoIpAddr = (std::stoi(smoIpOctets->octet1) << 24) |
(std::stoi(smoIpOctets->octet2) << 16) |
(std::stoi(smoIpOctets->octet3) << 8) |
std::stoi(smoIpOctets->octet4);
// Convert device IP octets to integers for bitwise operations
uint32_t deviceIpAddr = (std::stoi(deviceIpOctets->octet1) << 24) |
(std::stoi(deviceIpOctets->octet2) << 16) |
(std::stoi(deviceIpOctets->octet3) << 8) |
std::stoi(deviceIpOctets->octet4);
// Generate subnet mask based on nbits
uint32_t subnetMask = getSubnetMaskFor(smoSubnetNbits);
// Get all network interfaces using getifaddrs (Linux/Unix specific)
// TODO: Add Windows support using GetAdaptersAddresses when porting
/* Get all network interfaces using getifaddrs (Linux/Unix specific)
*
* FIXME: Add Windows support using GetAdaptersAddresses when porting
*/
struct ifaddrs *ifaddr;
if (getifaddrs(&ifaddr) == -1) {
return std::nullopt;
}
// Use unique_ptr for automatic cleanup (RAII)
// This ensures freeifaddrs is called even if we break out of the loop or throw an exception
// Use unique_ptr for automatic cleanup (RAII) to free ifaddrs
auto ifaddr_deleter = [](struct ifaddrs* ptr) { freeifaddrs(ptr); };
std::unique_ptr<struct ifaddrs, decltype(ifaddr_deleter)> ifaddr_ptr(
ifaddr, ifaddr_deleter);
@@ -564,9 +573,12 @@ std::optional<std::string> Device::detectSmoIp()
(std::stoi(ipOctets->octet3) << 8) |
std::stoi(ipOctets->octet4);
// Check if IP matches the subnet using the calculated mask
// Only compare the bits that are set in the subnet mask
if ((ipAddr & subnetMask) == (smoIpAddr & subnetMask)) {
/* Check if this iface's IP is in the same subnet as the device's IP
* using the calculated mask. Only compare the bits that are set in
* the subnet mask.
*/
if ((ipAddr & subnetMask) == (deviceIpAddr & subnetMask))
{
found_ip = ip;
break; // Exit loop, let unique_ptr handle cleanup
}
@@ -584,23 +596,22 @@ std::optional<std::string> Device::detectSmoIp()
}
}
std::string Device::getSmoIp()
std::string Device::getSmoIp(const std::string& deviceIP)
{
// If smo-ip was provided, return it
if (!smoIp.empty()) {
return smoIp;
}
// Otherwise, try to detect it
auto detectedIp = detectSmoIp();
auto detectedIp = detectSmoIp(deviceIP);
if (detectedIp.has_value()) {
return detectedIp.value();
}
// If detection failed, throw an exception
throw std::runtime_error(
std::string(__func__) + ": Failed to detect SMO IP address for smoIp "
+ smoIp + " with subnet mask /" + std::to_string(smoSubnetNbits));
std::string(__func__) + ": Failed to detect SMO IP address for device "
+ deviceIP + " with subnet mask /" + std::to_string(smoSubnetNbits));
}
} // namespace livoxProto1
+2 -2
View File
@@ -83,8 +83,8 @@ private:
const std::string& broadcastCode);
// IP detection methods
std::optional<std::string> detectSmoIp();
std::string getSmoIp();
std::optional<std::string> detectSmoIp(const std::string& deviceIP);
std::string getSmoIp(const std::string& deviceIP);
uint32_t getSubnetMaskFor(uint8_t nbits);
// Heartbeat mechanism