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 15, 2024
1 parent a82b297 commit 6fed725
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 6fed725

Please sign in to comment.