Skip to content

Commit

Permalink
core: always convert hostname to IP for UDP remotes
Browse files Browse the repository at this point in the history
Otherwise we end up with two connections, one for the hostname that we
add and one for the IP where we receive messages from.
  • Loading branch information
julianoes committed Nov 13, 2024
1 parent a81d258 commit 04f937e
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/mavsdk/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ target_sources(mavsdk
file_cache.cpp
flight_mode.cpp
fs_utils.cpp
hostname_to_ip.cpp
inflate_lzma.cpp
math_conversions.cpp
mavsdk.cpp
Expand Down Expand Up @@ -85,8 +86,9 @@ if (NOT BUILD_WITHOUT_CURL)
)

list(APPEND UNIT_TEST_SOURCES
# TODO: add this again
${PROJECT_SOURCE_DIR}/mavsdk/core/curl_test.cpp
${PROJECT_SOURCE_DIR}/mavsdk/core/hostname_to_ip_test.cpp
# TODO: add this again
#${PROJECT_SOURCE_DIR}/mavsdk/core/http_loader_test.cpp
)
else()
Expand Down
65 changes: 65 additions & 0 deletions src/mavsdk/core/hostname_to_ip.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "hostname_to_ip.h"
#include "log.h"

#include <cstring>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netinet/in.h>

#if defined(WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#endif

namespace mavsdk {

std::optional<std::string> resolve_hostname_to_ip(const std::string& hostname)
{
#if defined(WINDOWS)
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed" << std::endl;
return "";
}
#endif

addrinfo hints{};
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

addrinfo* result = nullptr;
int res = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
if (res != 0) {
#if defined(WINDOWS)
LogErr() << "getaddrinfo failed: " << WSAGetLastError();
#else
LogErr() << "getaddrinfo failed: " << gai_strerror(res);
#endif
#if defined(WINDOWS)
WSACleanup();
#endif
return {};
}

std::string ipAddress;
for (addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
sockaddr_in* sockaddrIpv4 = reinterpret_cast<sockaddr_in*>(ptr->ai_addr);
char ipStr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(sockaddrIpv4->sin_addr), ipStr, INET_ADDRSTRLEN);
ipAddress = ipStr;
break; // Take the first result
}

freeaddrinfo(result);
#if defined(WINDOWS)
WSACleanup();
#endif
return {ipAddress};
}

} // namespace mavsdk
10 changes: 10 additions & 0 deletions src/mavsdk/core/hostname_to_ip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <string>
#include <optional>

namespace mavsdk {

std::optional<std::string> resolve_hostname_to_ip(const std::string& hostname);

} // namespace mavsdk
34 changes: 34 additions & 0 deletions src/mavsdk/core/hostname_to_ip_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "hostname_to_ip.h"
#include <gtest/gtest.h>

using namespace mavsdk;

TEST(HostnameToIp, Localhost)
{
auto host = "localhost";
auto ip = resolve_hostname_to_ip(host);
ASSERT_TRUE(ip);
EXPECT_EQ(ip.value(), "127.0.0.1");
}

TEST(HostnameToIp, Ip)
{
auto host = "127.0.0.1";
auto ip = resolve_hostname_to_ip(host);
ASSERT_TRUE(ip);
EXPECT_EQ(ip.value(), host);
}

TEST(HostnameToIp, Empty)
{
auto host = "";
auto ip = resolve_hostname_to_ip(host);
EXPECT_FALSE(ip);
}

TEST(HostnameToIp, Something)
{
auto host = "something";
auto ip = resolve_hostname_to_ip(host);
EXPECT_FALSE(ip);
}
11 changes: 10 additions & 1 deletion src/mavsdk/core/mavsdk_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "plugin_base.h"
#include "mavlink_channels.h"
#include "callback_list.tpp"
#include "hostname_to_ip.h"

namespace mavsdk {

Expand Down Expand Up @@ -538,7 +539,15 @@ MavsdkImpl::add_udp_connection(const CliArg::Udp& udp, ForwardingOption forwardi
auto handle = add_connection(new_conn);

if (udp.mode == CliArg::Udp::Mode::Out) {
new_conn->add_remote(udp.host, udp.port);
// We need to add the IP rather than a hostname, otherwise we end up with two remotes:
// one for the IP, and one for a hostname.
auto remote_ip = resolve_hostname_to_ip(udp.host);

if (!remote_ip) {
return {ConnectionResult::DestinationIpUnknown, Mavsdk::ConnectionHandle{}};
}

new_conn->add_remote(remote_ip.value(), udp.port);
std::lock_guard<std::recursive_mutex> lock(_systems_mutex);

// With a UDP remote, we need to initiate the connection by sending heartbeats.
Expand Down

0 comments on commit 04f937e

Please sign in to comment.