diff --git a/src/mavsdk/core/CMakeLists.txt b/src/mavsdk/core/CMakeLists.txt index a9a56799b..4103e6b36 100644 --- a/src/mavsdk/core/CMakeLists.txt +++ b/src/mavsdk/core/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(mavsdk system_impl.cpp flight_mode.cpp fs_utils.cpp + hostname_to_ip.cpp inflate_lzma.cpp math_conversions.cpp mavsdk.cpp @@ -82,8 +83,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() diff --git a/src/mavsdk/core/hostname_to_ip.cpp b/src/mavsdk/core/hostname_to_ip.cpp new file mode 100644 index 000000000..d008211a6 --- /dev/null +++ b/src/mavsdk/core/hostname_to_ip.cpp @@ -0,0 +1,60 @@ +#include "hostname_to_ip.h" +#include "log.h" + +#if defined(WINDOWS) +#include +#include +#pragma comment(lib, "ws2_32.lib") +#else +#include +#include +#include +#include +#endif + +namespace mavsdk { + +std::optional 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(); + WSACleanup(); +#else + LogErr() << "getaddrinfo failed: " << gai_strerror(res); +#endif + return {}; + } + + std::string ipAddress; + for (addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next) { + sockaddr_in* sockaddrIpv4 = reinterpret_cast(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 diff --git a/src/mavsdk/core/hostname_to_ip.h b/src/mavsdk/core/hostname_to_ip.h new file mode 100644 index 000000000..8bedd6425 --- /dev/null +++ b/src/mavsdk/core/hostname_to_ip.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace mavsdk { + +std::optional resolve_hostname_to_ip(const std::string& hostname); + +} // namespace mavsdk diff --git a/src/mavsdk/core/hostname_to_ip_test.cpp b/src/mavsdk/core/hostname_to_ip_test.cpp new file mode 100644 index 000000000..1f716c632 --- /dev/null +++ b/src/mavsdk/core/hostname_to_ip_test.cpp @@ -0,0 +1,34 @@ +#include "hostname_to_ip.h" +#include + +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); +} diff --git a/src/mavsdk/core/mavsdk_impl.cpp b/src/mavsdk/core/mavsdk_impl.cpp index 3c7d9bcd5..a197ad8c3 100644 --- a/src/mavsdk/core/mavsdk_impl.cpp +++ b/src/mavsdk/core/mavsdk_impl.cpp @@ -14,6 +14,7 @@ #include "server_component_impl.h" #include "mavlink_channels.h" #include "callback_list.tpp" +#include "hostname_to_ip.h" namespace mavsdk { @@ -573,7 +574,14 @@ std::pair MavsdkImpl::setup_udp_remo } ConnectionResult ret = new_conn->start(); if (ret == ConnectionResult::Success) { - new_conn->add_remote(remote_ip, remote_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 always_ip = resolve_hostname_to_ip(remote_ip); + + if (!always_ip) { + return {ConnectionResult::DestinationIpUnknown, Mavsdk::ConnectionHandle{}}; + } + new_conn->add_remote(always_ip.value(), remote_port); auto handle = add_connection(new_conn); std::lock_guard lock(_systems_mutex);