SDL_net: haiku: Add support for network interface change notifications.

From ab94a6d2b23d2839827c0d49ada251a2e9bd33d6 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 25 May 2026 01:41:18 -0400
Subject: [PATCH] haiku: Add support for network interface change
 notifications.

Fixes #166.
---
 CMakeLists.txt        | 16 +++++----
 src/SDL_net.c         | 11 ++++--
 src/SDL_net_haiku.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 8 deletions(-)
 create mode 100644 src/SDL_net_haiku.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ab2e73..e14eaa2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,6 +104,12 @@ endif()
 set(PC_LIBS)
 set(PC_REQUIRES)
 
+if(HAIKU)
+    set(HAVE_GETIFADDRS True)  # Haiku always has it (but you have to -lnetwork, so check_c_source_compiles won't work as-is).
+    set(EXTRA_SOURCES "src/SDL_net_haiku.cpp")
+    enable_language(CXX)
+endif()
+
 set(PLATFORM_UNSUPPORTED False)
 if (DOS OR EMSCRIPTEN)  # These either don't have networking at all, or have needs we don't currently meet.
     set(PLATFORM_UNSUPPORTED True)
@@ -114,12 +120,10 @@ if(SDLNET_STUB_ONLY)
     message(WARNING "Only building a stub library. The functions will be there but all of them will fail!")
     add_library(${sdl3_net_target_name} src/SDL_net_stub_only.c)
 else()
-    add_library(${sdl3_net_target_name} src/SDL_net.c)
+    add_library(${sdl3_net_target_name} src/SDL_net.c ${EXTRA_SOURCES})
 endif()
 
-if(HAIKU)
-    set(HAVE_GETIFADDRS True)  # Haiku always has it (but you have to -lnetwork, so check_c_source_compiles won't work as-is).
-elseif(NOT (WIN32 OR SDLNET_STUB_ONLY))
+if(NOT (HAIKU OR WIN32 OR SDLNET_STUB_ONLY))
     check_c_source_compiles("
         #include <ifaddrs.h>
         int main(void) {
@@ -173,8 +177,8 @@ if(WIN32)
     target_link_libraries(${sdl3_net_target_name} PRIVATE iphlpapi ws2_32)
     list(APPEND PC_LIBS -liphlpapi -lws2_32)
 endif()
-if(CMAKE_SYSTEM_NAME MATCHES "Haiku.*")
-    target_link_libraries(${sdl3_net_target_name} PRIVATE network)
+if(HAIKU)
+    target_link_libraries(${sdl3_net_target_name} PRIVATE network be bnetapi)
 endif()
 set_target_properties(${sdl3_net_target_name} PROPERTIES
     OUTPUT_NAME "SDL3_net"
diff --git a/src/SDL_net.c b/src/SDL_net.c
index 03dcd03..f52b7e6 100644
--- a/src/SDL_net.c
+++ b/src/SDL_net.c
@@ -491,13 +491,16 @@ static void RefreshInterfaces(void)  // WINDOWS VERSION
 // AF_NETLINK covers Linux (and by extension Android). PF_ROUTE covers the BSDs (and by extension Apple platforms).
 // This doesn't cover all Unix platforms that ever existed, but this hits just about everything that is still being maintained seriously.
 
-#if defined(USE_NETLINK) || defined(PF_ROUTE)
+#if defined(SDL_PLATFORM_HAIKU)  // haiku has its own thing for monitoring, but needs getifaddrs.
+extern bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed);
+extern void NET_HAIKU_QuitInterfaceChangeNotifications(void);
+#elif defined(USE_NETLINK) || defined(PF_ROUTE)
 #define USE_NETWORK_MONITOR 1
 #else
 #warning unknown network monitoring system for this platform - will not report network changes
 #endif
 
-#ifdef USE_NETWORK_MONITOR
+#if defined(USE_NETWORK_MONITOR)
 static SDL_Thread *interface_change_notifications_thread = NULL;
 static SDL_AtomicInt interface_change_notifications_flag;  // !!! FIXME
 
@@ -572,6 +575,8 @@ static bool InitInterfaceChangeNotifications(void)  // LINUX/BSD VERSION
 #ifdef USE_NETWORK_MONITOR
     interface_change_notifications_thread = SDL_CreateThread(LinuxInterfaceChangeNotificationThread, "SDLNetIfaceEnum", NULL);
     return (interface_change_notifications_thread != NULL);
+#elif defined(SDL_PLATFORM_HAIKU)
+    return NET_HAIKU_InitInterfaceChangeNotifications(&interfaces_have_changed);
 #else
     return true;
 #endif
@@ -586,6 +591,8 @@ static void QuitInterfaceChangeNotifications(void)  // LINUX/BSD VERSION
         SDL_SetAtomicInt(&interface_change_notifications_flag, 0);
     }
     interface_change_notifications_thread = NULL;
+#elif defined(SDL_PLATFORM_HAIKU)
+    NET_HAIKU_QuitInterfaceChangeNotifications();
 #endif
 }
 
diff --git a/src/SDL_net_haiku.cpp b/src/SDL_net_haiku.cpp
new file mode 100644
index 0000000..dcb3f60
--- /dev/null
+++ b/src/SDL_net_haiku.cpp
@@ -0,0 +1,82 @@
+/*
+  SDL_net: A simple networking library for use with SDL
+  Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+// we use a little bit of C++ for Haiku support, since the system frameworks
+//  require it. Specifically, we need to get network interface change
+//  notifications through BNetworkRoster.
+
+#include <AppKit.h>
+#include <NetworkNotifications.h>
+
+#include <SDL3/SDL.h>
+
+extern "C" {
+    extern bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed);
+    extern void NET_HAIKU_QuitInterfaceChangeNotifications(void);
+}
+
+class NET_InterfaceLooper : public BLooper
+{
+public:
+    NET_InterfaceLooper(SDL_AtomicInt *_changed);
+    virtual void MessageReceived(BMessage *message);
+    virtual ~NET_InterfaceLooper() {}
+
+private:
+    SDL_AtomicInt *changed;
+};
+
+
+NET_InterfaceLooper::NET_InterfaceLooper(SDL_AtomicInt *_changed)
+    : BLooper("NET_InterfaceLooper")
+    , changed(_changed)
+{
+}
+
+void NET_InterfaceLooper::MessageReceived(BMessage *message)
+{
+    //SDL_Log("NET_InterfaceLooper::MessageReceived %d", (int) message->what);
+    SDL_SetAtomicInt(changed, 1);
+    BLooper::MessageReceived(message);
+}
+
+
+static NET_InterfaceLooper *looper = NULL;
+
+bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed)
+{
+    SDL_assert(!looper);
+    looper = new NET_InterfaceLooper(changed);
+    looper->Run();
+    return start_watching_network(
+        B_NETWORK_INTERFACE_ADDED | B_NETWORK_INTERFACE_REMOVED |
+        B_NETWORK_INTERFACE_CHANGED | B_NETWORK_DEVICE_LINK_CHANGED, looper
+    ) == B_OK;
+}
+
+void NET_HAIKU_QuitInterfaceChangeNotifications(void)
+{
+    if (looper) {
+        looper->PostMessage(B_QUIT_REQUESTED);
+        looper = NULL;
+    }
+}
+