From b6f1cc4bc87912b228e63acea44ef6b0d61a3e4d Mon Sep 17 00:00:00 2001
From: Mike Black W9MDB <mdblack98@yahoo.com>
Date: Sun, 7 May 2023 10:59:43 -0500
Subject: [PATCH] Attempt to get multicastclient working on mingw
 https://github.com/Hamlib/Hamlib/issues/695

---
 src/multicast.c         |   3 +-
 tests/multicastclient.c | 112 ++++++++++++++++++++++++----------------
 2 files changed, 69 insertions(+), 46 deletions(-)

diff --git a/src/multicast.c b/src/multicast.c
index 2b50055fb..639b2a409 100644
--- a/src/multicast.c
+++ b/src/multicast.c
@@ -317,6 +317,7 @@ int multicast_init(RIG *rig, char *addr, int port)
     rig->state.multicast->runflag = 1;
     pthread_create(&rig->state.multicast->threadid, NULL, multicast_thread,
                    (void *)rig);
+    printf("threadid=%ld\n", rig->state.multicast->threadid);
     rig->state.multicast->multicast_running = 1;
     return RIG_OK;
 }
@@ -390,7 +391,7 @@ int main(int argc, char *argv[])
     strncpy(rig->state.rigport.pathname, "/dev/ttyUSB0", HAMLIB_FILPATHLEN - 1);
     rig->state.rigport.parm.serial.rate = 38400;
     rig_open(rig);
-    multicast_init(rig, NULL, 0);
+    multicast_init(rig, "224.0.0.1", 4532);
     pthread_join(rig->state.multicast->threadid, NULL);
     pthread_exit(NULL);
     return 0;
diff --git a/tests/multicastclient.c b/tests/multicastclient.c
index d5a6f5a30..c0c171ae5 100644
--- a/tests/multicastclient.c
+++ b/tests/multicastclient.c
@@ -1,88 +1,110 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 
-#define MULTICAST_ADDR "224.0.0.1"
-#define PORT 4532
-#define BUFFER_SIZE 1024
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#pragma comment(lib, "Ws2_32.lib")
+#else
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#endif
+
+#define MCAST_PORT 4532
+#define MCAST_ADDR "224.0.0.1"
+#define BUFFER_SIZE 4096
 
 int main()
 {
-    // Create a UDP socket
-    int sock = socket(AF_INET, SOCK_DGRAM, 0);
+    int sock;
+    struct sockaddr_in mcast_addr;
+    char buffer[BUFFER_SIZE];
+    int bytes_received;
 
-    if (sock < 0)
+#ifdef _WIN32
+    WSADATA wsaData;
+
+    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
     {
-        perror("socket creation failed");
+        fprintf(stderr, "WSAStartup failed: %d\n", WSAGetLastError());
+        return 1;
+    }
+
+#endif
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+    {
+        perror("socket() failed");
         exit(EXIT_FAILURE);
     }
 
     // Set the SO_REUSEADDR option to allow multiple processes to use the same address
     int optval = 1;
 
-    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval,
+                   sizeof(optval)) < 0)
     {
-        perror("setsockopt failed");
+        //rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
+        //return -RIG_EIO;
+        return 1;
+    }
+
+
+    memset(&mcast_addr, 0, sizeof(mcast_addr));
+    mcast_addr.sin_family = AF_INET;
+    mcast_addr.sin_port = htons(MCAST_PORT);
+    mcast_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    if (bind(sock, (struct sockaddr *)&mcast_addr, sizeof(mcast_addr)) < 0)
+    {
+        perror("bind() failed");
         exit(EXIT_FAILURE);
     }
 
-    // Bind the socket to any available local address and the specified port
-    struct sockaddr_in addr = {0};
-    addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    addr.sin_port = htons(PORT);
+    struct ip_mreq mreq;
 
-    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
-    {
-        perror("bind failed");
-        exit(EXIT_FAILURE);
-    }
+    mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR);
 
-    // Construct the multicast group address
-    struct ip_mreq mreq = {0};
-    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDR);
     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
 
-    // Join the multicast group
-    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq,
+                   sizeof(mreq)) < 0)
     {
-        perror("setsockopt failed");
+        perror("setsockopt() failed");
         exit(EXIT_FAILURE);
     }
 
-    // Receive multicast packets in a loop
     while (1)
     {
-        char buffer[BUFFER_SIZE];
-        struct sockaddr_in src_addr = {0};
-        socklen_t addrlen = sizeof(src_addr);
-        ssize_t num_bytes = recvfrom(sock, buffer, BUFFER_SIZE - 1, 0,
-                                     (struct sockaddr *)&src_addr, &addrlen);
+        bytes_received = recvfrom(sock, buffer, BUFFER_SIZE, 0, NULL, 0);
 
-        if (num_bytes < 0)
+        if (bytes_received < 0)
         {
-            perror("recvfrom failed");
-            exit(EXIT_FAILURE);
+            perror("recvfrom() failed");
+            break;
         }
 
-        buffer[num_bytes] = '\0';
-        printf("Received %zd bytes from %s:%d\n%s\n", num_bytes,
-               inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port), buffer);
+        buffer[bytes_received] = '\0';
+        printf("Received: %s\n", buffer);
     }
 
-    // Leave the multicast group
-    if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+    // Drop membership before closing the socket
+    if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq,
+                   sizeof(mreq)) < 0)
     {
-        perror("setsockopt failed");
-        exit(EXIT_FAILURE);
+        perror("setsockopt() failed");
     }
 
-    // Close the socket
     close(sock);
+#ifdef _WIN32
+    WSACleanup();
+#endif
 
     return 0;
 }
+