From 8327bf57218751d3343dd97f55059caff103253a Mon Sep 17 00:00:00 2001 From: Eric Xiao Date: Mon, 22 Jun 2026 09:59:06 -0700 Subject: [PATCH 1/3] Add loopback interface helper for macos --- src/software/logger/BUILD | 1 + src/software/logger/plotjuggler_sink.h | 3 ++- src/software/networking/udp/BUILD | 2 ++ src/software/networking/udp/network_utils.cpp | 9 +++++++++ src/software/networking/udp/network_utils.h | 7 +++++++ src/software/networking/udp/network_utils_test.cpp | 2 +- .../udp/threaded_proto_udp_listener_test.cpp | 10 ++++++---- .../networking/udp/threaded_proto_udp_sender_test.cpp | 4 +++- 8 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/software/logger/BUILD b/src/software/logger/BUILD index 6fa65a6909..2241f48d02 100644 --- a/src/software/logger/BUILD +++ b/src/software/logger/BUILD @@ -146,6 +146,7 @@ cc_library( deps = [ "//proto:visualization_cc_proto", "//shared:constants", + "//software/networking/udp:network_utils", "//software/networking/udp:threaded_udp_sender", "@g3log", "@protobuf//:json_util", diff --git a/src/software/logger/plotjuggler_sink.h b/src/software/logger/plotjuggler_sink.h index 99b1a8583b..faf35a0d31 100644 --- a/src/software/logger/plotjuggler_sink.h +++ b/src/software/logger/plotjuggler_sink.h @@ -5,6 +5,7 @@ #include "proto/visualization.pb.h" #include "software/logger/custom_logging_levels.h" +#include "software/networking/udp/network_utils.h" #include "software/networking/udp/threaded_udp_sender.h" @@ -20,7 +21,7 @@ class PlotJugglerSink * * @param interface The interface to send Plotjuggler UDP packets on */ - PlotJugglerSink(const std::string& interface = "lo"); + PlotJugglerSink(const std::string& interface = getLoopbackInterfaceName()); ~PlotJugglerSink() = default; diff --git a/src/software/networking/udp/BUILD b/src/software/networking/udp/BUILD index 5e78de1f29..8a08240030 100644 --- a/src/software/networking/udp/BUILD +++ b/src/software/networking/udp/BUILD @@ -67,6 +67,7 @@ cc_test( "threaded_proto_udp_listener_test.cpp", ], deps = [ + ":network_utils", ":threaded_proto_udp_listener", "//shared/test_util:tbots_gtest_main", "@protobuf//:empty_cc_proto", @@ -89,6 +90,7 @@ cc_test( "threaded_proto_udp_sender_test.cpp", ], deps = [ + ":network_utils", ":threaded_proto_udp_sender", "//shared/test_util:tbots_gtest_main", "@protobuf//:empty_cc_proto", diff --git a/src/software/networking/udp/network_utils.cpp b/src/software/networking/udp/network_utils.cpp index b8f270bc23..214b5fce98 100644 --- a/src/software/networking/udp/network_utils.cpp +++ b/src/software/networking/udp/network_utils.cpp @@ -2,6 +2,15 @@ #include +std::string getLoopbackInterfaceName() +{ +#ifdef __APPLE__ + return "lo0"; +#else + return "lo"; +#endif +} + std::optional getLocalIp(const std::string& interface, bool ipv4) { struct ifaddrs* ifAddrStruct = nullptr; diff --git a/src/software/networking/udp/network_utils.h b/src/software/networking/udp/network_utils.h index bedfcf4d7b..bd03226967 100644 --- a/src/software/networking/udp/network_utils.h +++ b/src/software/networking/udp/network_utils.h @@ -5,6 +5,13 @@ #include #include +/** + * Get the name of the loopback network interface for the current platform. + * + * @return the loopback interface name for the current platform + */ +std::string getLoopbackInterfaceName(); + /** * Given an interface, get the IP address associated with that interface * diff --git a/src/software/networking/udp/network_utils_test.cpp b/src/software/networking/udp/network_utils_test.cpp index 52cc8b8c32..6dfd91bb86 100644 --- a/src/software/networking/udp/network_utils_test.cpp +++ b/src/software/networking/udp/network_utils_test.cpp @@ -4,7 +4,7 @@ TEST(NetworkUtilsTest, getLocalIpValidInterface) { - std::string interface = "lo"; + std::string interface = getLoopbackInterfaceName(); std::optional local_ip = getLocalIp(interface, true); EXPECT_TRUE(local_ip); EXPECT_EQ(local_ip.value(), "127.0.0.1"); diff --git a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp index 70bac1ae1e..855e94bc2a 100644 --- a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp +++ b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp @@ -4,6 +4,7 @@ #include "google/protobuf/empty.pb.h" #include "software/networking/tbots_network_exception.h" +#include "software/networking/udp/network_utils.h" TEST(ThreadedProtoUdpListenerTest, error_finding_local_ip_address) { @@ -16,13 +17,14 @@ TEST(ThreadedProtoUdpListenerTest, error_finding_local_ip_address) TEST(ThreadedProtoUdpListenerTest, error_creating_socket) { // This will always fail because it requires root privileges to open this port - EXPECT_THROW(ThreadedProtoUdpListener( - "224.5.23.1", 1023, "lo", [](const auto&) {}, true), - TbotsNetworkException); + EXPECT_THROW( + ThreadedProtoUdpListener( + "224.5.23.1", 1023, getLoopbackInterfaceName(), [](const auto&) {}, true), + TbotsNetworkException); } TEST(ThreadedProtoUdpListenerTest, no_error_creating_socket) { ThreadedProtoUdpListener( - "224.5.23.0", 40000, "lo", [](const auto&) {}, true); + "224.5.23.0", 40000, getLoopbackInterfaceName(), [](const auto&) {}, true); } diff --git a/src/software/networking/udp/threaded_proto_udp_sender_test.cpp b/src/software/networking/udp/threaded_proto_udp_sender_test.cpp index f9c04d1322..81ee08bca6 100644 --- a/src/software/networking/udp/threaded_proto_udp_sender_test.cpp +++ b/src/software/networking/udp/threaded_proto_udp_sender_test.cpp @@ -4,6 +4,7 @@ #include "google/protobuf/empty.pb.h" #include "software/networking/tbots_network_exception.h" +#include "software/networking/udp/network_utils.h" TEST(ThreadedProtoUdpSenderTest, error_finding_local_ip_address) { @@ -14,5 +15,6 @@ TEST(ThreadedProtoUdpSenderTest, error_finding_local_ip_address) TEST(ThreadedProtoUdpSenderTest, no_error_creating_socket) { - ThreadedProtoUdpSender("224.5.23.1", 40000, "lo", true); + ThreadedProtoUdpSender("224.5.23.1", 40000, + getLoopbackInterfaceName(), true); } From e0e5f06f9f8eb9b95b2be918ec94f9dbab201703 Mon Sep 17 00:00:00 2001 From: Eric Xiao Date: Wed, 24 Jun 2026 10:42:26 -0700 Subject: [PATCH 2/3] Define LOOPBACK_INTERFACE constant instead of helper function --- src/shared/constants.h | 7 +++++++ src/software/logger/BUILD | 1 - src/software/logger/plotjuggler_sink.h | 4 ++-- src/software/networking/udp/BUILD | 5 +++-- src/software/networking/udp/network_utils.cpp | 9 --------- src/software/networking/udp/network_utils.h | 7 ------- src/software/networking/udp/network_utils_test.cpp | 4 +++- .../networking/udp/threaded_proto_udp_listener_test.cpp | 6 +++--- .../networking/udp/threaded_proto_udp_sender_test.cpp | 4 ++-- 9 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/shared/constants.h b/src/shared/constants.h index ed94c0cde9..9310434047 100644 --- a/src/shared/constants.h +++ b/src/shared/constants.h @@ -22,6 +22,13 @@ static const std::unordered_map ROBOT_MULTICAST_CHANNELS = { {12, "ff02::c3d0:42d2:bb12"}, {13, "ff02::c3d0:42d2:bb13"}, {14, "ff02::c3d0:42d2:bb14"}, {15, "ff02::c3d0:42d2:bb15"}}; +// the name of the loopback network interface, which differs across platforms +#ifdef __APPLE__ +static const std::string LOOPBACK_INTERFACE = "lo0"; +#else +static const std::string LOOPBACK_INTERFACE = "lo"; +#endif + // PlotJuggler's default host and port static const std::string PLOTJUGGLER_GUI_DEFAULT_HOST = "ff02::c3d0:42d2:aaaa"; static const short unsigned int PLOTJUGGLER_GUI_DEFAULT_PORT = 9870; diff --git a/src/software/logger/BUILD b/src/software/logger/BUILD index 2241f48d02..6fa65a6909 100644 --- a/src/software/logger/BUILD +++ b/src/software/logger/BUILD @@ -146,7 +146,6 @@ cc_library( deps = [ "//proto:visualization_cc_proto", "//shared:constants", - "//software/networking/udp:network_utils", "//software/networking/udp:threaded_udp_sender", "@g3log", "@protobuf//:json_util", diff --git a/src/software/logger/plotjuggler_sink.h b/src/software/logger/plotjuggler_sink.h index faf35a0d31..14b3919c9f 100644 --- a/src/software/logger/plotjuggler_sink.h +++ b/src/software/logger/plotjuggler_sink.h @@ -4,8 +4,8 @@ #include #include "proto/visualization.pb.h" +#include "shared/constants.h" #include "software/logger/custom_logging_levels.h" -#include "software/networking/udp/network_utils.h" #include "software/networking/udp/threaded_udp_sender.h" @@ -21,7 +21,7 @@ class PlotJugglerSink * * @param interface The interface to send Plotjuggler UDP packets on */ - PlotJugglerSink(const std::string& interface = getLoopbackInterfaceName()); + PlotJugglerSink(const std::string& interface = LOOPBACK_INTERFACE); ~PlotJugglerSink() = default; diff --git a/src/software/networking/udp/BUILD b/src/software/networking/udp/BUILD index 8a08240030..05244d26ff 100644 --- a/src/software/networking/udp/BUILD +++ b/src/software/networking/udp/BUILD @@ -17,6 +17,7 @@ cc_test( ], deps = [ ":network_utils", + "//shared:constants", "//shared/test_util:tbots_gtest_main", ], ) @@ -67,8 +68,8 @@ cc_test( "threaded_proto_udp_listener_test.cpp", ], deps = [ - ":network_utils", ":threaded_proto_udp_listener", + "//shared:constants", "//shared/test_util:tbots_gtest_main", "@protobuf//:empty_cc_proto", ], @@ -90,8 +91,8 @@ cc_test( "threaded_proto_udp_sender_test.cpp", ], deps = [ - ":network_utils", ":threaded_proto_udp_sender", + "//shared:constants", "//shared/test_util:tbots_gtest_main", "@protobuf//:empty_cc_proto", ], diff --git a/src/software/networking/udp/network_utils.cpp b/src/software/networking/udp/network_utils.cpp index 214b5fce98..b8f270bc23 100644 --- a/src/software/networking/udp/network_utils.cpp +++ b/src/software/networking/udp/network_utils.cpp @@ -2,15 +2,6 @@ #include -std::string getLoopbackInterfaceName() -{ -#ifdef __APPLE__ - return "lo0"; -#else - return "lo"; -#endif -} - std::optional getLocalIp(const std::string& interface, bool ipv4) { struct ifaddrs* ifAddrStruct = nullptr; diff --git a/src/software/networking/udp/network_utils.h b/src/software/networking/udp/network_utils.h index bd03226967..bedfcf4d7b 100644 --- a/src/software/networking/udp/network_utils.h +++ b/src/software/networking/udp/network_utils.h @@ -5,13 +5,6 @@ #include #include -/** - * Get the name of the loopback network interface for the current platform. - * - * @return the loopback interface name for the current platform - */ -std::string getLoopbackInterfaceName(); - /** * Given an interface, get the IP address associated with that interface * diff --git a/src/software/networking/udp/network_utils_test.cpp b/src/software/networking/udp/network_utils_test.cpp index 6dfd91bb86..e9ede4cfd8 100644 --- a/src/software/networking/udp/network_utils_test.cpp +++ b/src/software/networking/udp/network_utils_test.cpp @@ -2,9 +2,11 @@ #include +#include "shared/constants.h" + TEST(NetworkUtilsTest, getLocalIpValidInterface) { - std::string interface = getLoopbackInterfaceName(); + std::string interface = LOOPBACK_INTERFACE; std::optional local_ip = getLocalIp(interface, true); EXPECT_TRUE(local_ip); EXPECT_EQ(local_ip.value(), "127.0.0.1"); diff --git a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp index 855e94bc2a..655eddb0af 100644 --- a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp +++ b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp @@ -3,8 +3,8 @@ #include #include "google/protobuf/empty.pb.h" +#include "shared/constants.h" #include "software/networking/tbots_network_exception.h" -#include "software/networking/udp/network_utils.h" TEST(ThreadedProtoUdpListenerTest, error_finding_local_ip_address) { @@ -19,12 +19,12 @@ TEST(ThreadedProtoUdpListenerTest, error_creating_socket) // This will always fail because it requires root privileges to open this port EXPECT_THROW( ThreadedProtoUdpListener( - "224.5.23.1", 1023, getLoopbackInterfaceName(), [](const auto&) {}, true), + "224.5.23.1", 1023, LOOPBACK_INTERFACE, [](const auto&) {}, true), TbotsNetworkException); } TEST(ThreadedProtoUdpListenerTest, no_error_creating_socket) { ThreadedProtoUdpListener( - "224.5.23.0", 40000, getLoopbackInterfaceName(), [](const auto&) {}, true); + "224.5.23.0", 40000, LOOPBACK_INTERFACE, [](const auto&) {}, true); } diff --git a/src/software/networking/udp/threaded_proto_udp_sender_test.cpp b/src/software/networking/udp/threaded_proto_udp_sender_test.cpp index 81ee08bca6..893926d3cc 100644 --- a/src/software/networking/udp/threaded_proto_udp_sender_test.cpp +++ b/src/software/networking/udp/threaded_proto_udp_sender_test.cpp @@ -3,8 +3,8 @@ #include #include "google/protobuf/empty.pb.h" +#include "shared/constants.h" #include "software/networking/tbots_network_exception.h" -#include "software/networking/udp/network_utils.h" TEST(ThreadedProtoUdpSenderTest, error_finding_local_ip_address) { @@ -16,5 +16,5 @@ TEST(ThreadedProtoUdpSenderTest, error_finding_local_ip_address) TEST(ThreadedProtoUdpSenderTest, no_error_creating_socket) { ThreadedProtoUdpSender("224.5.23.1", 40000, - getLoopbackInterfaceName(), true); + LOOPBACK_INTERFACE, true); } From 67eabd28da0378da299d405542145259f85df076 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:55:38 +0000 Subject: [PATCH 3/3] [pre-commit.ci lite] apply automatic fixes --- .../networking/udp/threaded_proto_udp_listener_test.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp index 655eddb0af..9b15496a06 100644 --- a/src/software/networking/udp/threaded_proto_udp_listener_test.cpp +++ b/src/software/networking/udp/threaded_proto_udp_listener_test.cpp @@ -17,10 +17,9 @@ TEST(ThreadedProtoUdpListenerTest, error_finding_local_ip_address) TEST(ThreadedProtoUdpListenerTest, error_creating_socket) { // This will always fail because it requires root privileges to open this port - EXPECT_THROW( - ThreadedProtoUdpListener( - "224.5.23.1", 1023, LOOPBACK_INTERFACE, [](const auto&) {}, true), - TbotsNetworkException); + EXPECT_THROW(ThreadedProtoUdpListener( + "224.5.23.1", 1023, LOOPBACK_INTERFACE, [](const auto&) {}, true), + TbotsNetworkException); } TEST(ThreadedProtoUdpListenerTest, no_error_creating_socket)