Skip to content

Commit

Permalink
Merge pull request #2440 from mavlink/pr-hostname-to-ip
Browse files Browse the repository at this point in the history
core: always convert hostname to IP for UDP remotes
  • Loading branch information
julianoes authored Nov 15, 2024
2 parents a81d258 + d45cff9 commit 1e0a29e
Show file tree
Hide file tree
Showing 5 changed files with 117 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
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);
}
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 1e0a29e

Please sign in to comment.