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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user