From bd351e8d555001647e8501ac2d38c675a2a3c005 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roman=20Smr=C5=BE?= <roman.smrz@seznam.cz>
Date: Fri, 5 Jul 2024 11:07:27 +0200
Subject: Broadcast address lookup on Windows

---
 src/Erebos/Network.hs        | 16 ++++++++------
 src/Erebos/Network/ifaddrs.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+), 6 deletions(-)

(limited to 'src/Erebos')

diff --git a/src/Erebos/Network.hs b/src/Erebos/Network.hs
index 41b6279..3896829 100644
--- a/src/Erebos/Network.hs
+++ b/src/Erebos/Network.hs
@@ -301,10 +301,11 @@ startServer opt serverOrigHead logd' serverServices = do
 
             forkServerThread server $ forever $ do
                 (paddr, msg) <- readFlowIO serverRawPath
-                case paddr of
-                    DatagramAddress addr -> void $ S.sendTo sock msg addr
+                handle (\(e :: IOException) -> atomically . logd $ "failed to send packet to " ++ show paddr ++ ": " ++ show e) $ do
+                    case paddr of
+                        DatagramAddress addr -> void $ S.sendTo sock msg addr
 #ifdef ENABLE_ICE_SUPPORT
-                    PeerIceSession ice   -> iceSend ice msg
+                        PeerIceSession ice   -> iceSend ice msg
 #endif
 
             forkServerThread server $ forever $ do
@@ -922,6 +923,9 @@ getBroadcastAddresses port = do
             w <- peekElemOff ptr i
             if w == 0 then return []
                       else (SockAddrInet port w:) <$> parse (i + 1)
-    addrs <- parse 0
-    cFree ptr
-    return addrs
+    if ptr == nullPtr
+      then return []
+      else do
+        addrs <- parse 0
+        cFree ptr
+        return addrs
diff --git a/src/Erebos/Network/ifaddrs.c b/src/Erebos/Network/ifaddrs.c
index 37c3e00..efeca18 100644
--- a/src/Erebos/Network/ifaddrs.c
+++ b/src/Erebos/Network/ifaddrs.c
@@ -1,5 +1,7 @@
 #include "ifaddrs.h"
 
+#ifndef _WIN32
+
 #include <arpa/inet.h>
 #include <ifaddrs.h>
 #include <net/if.h>
@@ -39,3 +41,51 @@ uint32_t * broadcast_addresses(void)
 	ret[count] = 0;
 	return ret;
 }
+
+#else // _WIN32
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#pragma comment(lib, "ws2_32.lib")
+
+uint32_t * broadcast_addresses(void)
+{
+	uint32_t * ret = NULL;
+	SOCKET wsock = INVALID_SOCKET;
+
+	struct WSAData wsaData;
+	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
+		return NULL;
+
+	wsock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
+	if (wsock == INVALID_SOCKET)
+		goto cleanup;
+
+	INTERFACE_INFO InterfaceList[32];
+	unsigned long nBytesReturned;
+
+	if (WSAIoctl(wsock, SIO_GET_INTERFACE_LIST, 0, 0,
+				InterfaceList, sizeof(InterfaceList),
+				&nBytesReturned, 0, 0) == SOCKET_ERROR)
+		goto cleanup;
+
+	int numInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
+
+	size_t capacity = 16, count = 0;
+	ret = malloc(sizeof(uint32_t) * capacity);
+
+	for (int i = 0; i < numInterfaces && count < capacity - 1; i++)
+		if (InterfaceList[i].iiFlags & IFF_BROADCAST)
+			ret[count++] = InterfaceList[i].iiBroadcastAddress.AddressIn.sin_addr.s_addr;
+
+	ret[count] = 0;
+cleanup:
+	if (wsock != INVALID_SOCKET)
+		closesocket(wsock);
+	WSACleanup();
+
+	return ret;
+}
+
+#endif
-- 
cgit v1.2.3