Skip to content

Commit

Permalink
Merge pull request #2442 from mavlink/pr-v2.12-pr-hostname-to-ip
Browse files Browse the repository at this point in the history
[BACKPORT v2.12] core: always convert hostname to IP for UDP remotes
  • Loading branch information
julianoes authored Nov 15, 2024
2 parents a82b297 + 6fed725 commit e31106b
Show file tree
Hide file tree
Showing 5 changed files with 116 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 @@ -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
Expand Down Expand Up @@ -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()
Expand Down
60 changes: 60 additions & 0 deletions src/mavsdk/core/hostname_to_ip.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "hostname_to_ip.h"
#include "log.h"

#if defined(WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#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();
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<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);
}
10 changes: 9 additions & 1 deletion src/mavsdk/core/mavsdk_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "server_component_impl.h"
#include "mavlink_channels.h"
#include "callback_list.tpp"
#include "hostname_to_ip.h"

namespace mavsdk {

Expand Down Expand Up @@ -573,7 +574,14 @@ std::pair<ConnectionResult, Mavsdk::ConnectionHandle> 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<std::recursive_mutex> lock(_systems_mutex);

Expand Down

0 comments on commit e31106b

Please sign in to comment.