From 37420659f8e977b8488105dafced25335be7d23c Mon Sep 17 00:00:00 2001
From: brutzman <brutzman@nps.edu>
Date: Sat, 14 Aug 2021 17:31:21 -0700
Subject: [PATCH] improved handling of networkInterface

---
 .../src/OpenDis7Examples/AllPduReceiver.java  | 165 +++++++++---------
 .../src/OpenDis7Examples/AllPduSender.java    |  33 ++--
 2 files changed, 108 insertions(+), 90 deletions(-)

diff --git a/examples/src/OpenDis7Examples/AllPduReceiver.java b/examples/src/OpenDis7Examples/AllPduReceiver.java
index d413c2779a..8266f78b42 100644
--- a/examples/src/OpenDis7Examples/AllPduReceiver.java
+++ b/examples/src/OpenDis7Examples/AllPduReceiver.java
@@ -23,99 +23,106 @@ public class AllPduReceiver
 	/** Output prefix to identify this class */
     private final static String TRACE_PREFIX = "[" + AllPduReceiver.class.getName() + "] ";
 
-  /**
+    /**
      * Program invocation, execution starts here
      * @param args command-line arguments
      */
     public static void main(String args[])
-  {
-    MulticastSocket multicastSocket;
-    InetAddress     internetAddress;
-    PduFactory      pduFactory = new PduFactory();
+    {
+        MulticastSocket multicastSocket;
+        InetAddress     multicastInetAddress;
+        PduFactory      pduFactory = new PduFactory();
 
-    System.out.println(TRACE_PREFIX + "started...");
+        System.out.println(TRACE_PREFIX + "started...");
 
-    try {
-      if (args.length == 2)
-      {
-        internetAddress = InetAddress.getByName(args[0]);
-        multicastSocket  = new MulticastSocket(Integer.parseInt(args[1]));
-      }
-      else
-      {
-        System.out.println("Usage:   AllPduReceiver <multicast group> <port>");
-        System.out.println("Default: AllPduReceiver     " + DEFAULT_MULTICAST_ADDRESS + "      " + DEFAULT_MULTICAST_PORT);
-        multicastSocket  = new MulticastSocket(DEFAULT_MULTICAST_PORT);
-        internetAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS);
-      }
-      System.out.println("To quit: stop or kill this process");
-      multicastSocket.joinGroup(internetAddress);
+        try {
+            if (args.length == 2)
+            {
+                multicastInetAddress = InetAddress.getByName(args[0]);
+                multicastSocket  = new MulticastSocket(Integer.parseInt(args[1]));
+            }
+            else
+            {
+                System.out.println("Usage:   AllPduReceiver <multicast group> <port>");
+                System.out.println("Default: AllPduReceiver     " + DEFAULT_MULTICAST_ADDRESS + "      " + DEFAULT_MULTICAST_PORT);
+                multicastSocket  = new MulticastSocket(DEFAULT_MULTICAST_PORT);
+                multicastInetAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS);
+            }
+            System.out.println("To quit: stop or kill this process");
+    //      multicastSocket.joinGroup(multicastInetAddress); // deprecated
+
+            // =======================================================================
+            // new approach using interface
+            NetworkInterface networkInterface = NetworkInterface.getByInetAddress(multicastInetAddress);
+            SocketAddress localMulticastSocketAddress = new InetSocketAddress(multicastInetAddress, DEFAULT_MULTICAST_PORT);
+            multicastSocket.joinGroup(localMulticastSocketAddress, networkInterface);
+            // =======================================================================
 
-      byte buffer[]  = new byte[1500]; // typical MTU size in bytes
-        
-      while (true) // Loop infinitely, receiving datagrams
-      {
-        Arrays.fill(buffer, (byte)0);
-        DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length); // reset packet each time
-        multicastSocket.receive(datagramPacket);  // process blocks here until receipt of network packet with PDU
-//        datagramPacket.setLength(buffer.length);
+            byte buffer[]  = new byte[1500]; // typical MTU size in bytes
 
-//      Pdu pdu = pduFactory.createPdu(packet.getData()); // packet.getData() returns byte[] array data buffer
+            while (true) // Loop indefinitely, receiving datagrams
+            {
+                Arrays.fill(buffer, (byte)0);
+                DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length); // reset packet each time
+                multicastSocket.receive(datagramPacket);  // process blocks here until receipt of network packet with PDU
+        //        datagramPacket.setLength(buffer.length);
 
-        List<Pdu> pduBundle = pduFactory.getPdusFromBundle(datagramPacket.getData(),datagramPacket.getLength());
-        
-        if      (pduBundle.isEmpty())
-             System.out.println("Received PDU bundle is empty, packet.getData().length=" + datagramPacket.getData().length + ", error...");
-//      else if (pduBundle.size() == 1)// common case, typically unremarkable
-//           System.out.println("Received PDU bundle size is " + pduBundle.size());
-        else if (pduBundle.size() > 1)
-             System.out.println("Received PDU bundle size is " + pduBundle.size());
+        //      Pdu pdu = pduFactory.createPdu(packet.getData()); // packet.getData() returns byte[] array data buffer
 
-        for (Pdu nextPdu : pduBundle) // iterator loop through PDU bundle
-        {
-            DisPduType currentPduType       = nextPdu.getPduType(); //short  currentPduType = nextPdu.getPduType();
-            String     currentPduTypeName   = nextPdu.getClass().getName();
-            String     currentPduFamilyName = nextPdu.getClass().getSuperclass().getSimpleName();
-            DISProtocolFamily currentProtocolFamilyID = nextPdu.getProtocolFamily(); //short  currentProtocolFamilyID = nextPdu.getProtocolFamily();
- 
-            StringBuilder message = new StringBuilder();
-            message.append(DisTime.timeStampToString(nextPdu.getTimestamp())).append(" ");
-            message.append("received new DIS PDU ");
-            String currentPduTypePadded     = String.format("%-48s", currentPduType);     // - indicates right padding of whitespace
-            message.append(currentPduTypePadded);
-            // optional, verbose
-//            String currentPduTypeNamePadded = String.format("%-49s", currentPduTypeName); // - indicates right padding of whitespace
-//            message.append(" of type ").append(currentPduTypeNamePadded); // package.class name
-            message.append(" (").append(currentProtocolFamilyID);
-//          message.append(" ").append(currentPduFamilyName); // class name is also available
-            message.append(")");
-            System.out.println(message.toString()); // diagnostic information helps
+                List<Pdu> pduBundle = pduFactory.getPdusFromBundle(datagramPacket.getData(),datagramPacket.getLength());
 
-            // additional message information of interest, if any
-            switch (currentPduType) // using enumeration values from edu.​nps.​moves.​dis7.​enumerations.​DisPduType
-            {
-                case COMMENT:
-                    CommentPdu commentPdu = (CommentPdu)nextPdu; // cast to precise type
-                    ArrayList<VariableDatum> payloadList = (ArrayList)commentPdu.getVariableDatums();
-                    if (!payloadList.isEmpty())
-                        System.out.print  ("   messages: ");
-                    for (VariableDatum variableDatum : payloadList)
+                if      (pduBundle.isEmpty())
+                     System.out.println("Received PDU bundle is empty, packet.getData().length=" + datagramPacket.getData().length + ", error...");
+        //      else if (pduBundle.size() == 1)// common case, typically unremarkable
+        //           System.out.println("Received PDU bundle size is " + pduBundle.size());
+                else if (pduBundle.size() > 1)
+                     System.out.println("Received PDU bundle size is " + pduBundle.size());
+
+                for (Pdu nextPdu : pduBundle) // iterator loop through PDU bundle
+                {
+                    DisPduType currentPduType       = nextPdu.getPduType(); //short  currentPduType = nextPdu.getPduType();
+                    String     currentPduTypeName   = nextPdu.getClass().getName();
+                    String     currentPduFamilyName = nextPdu.getClass().getSuperclass().getSimpleName();
+                    DISProtocolFamily currentProtocolFamilyID = nextPdu.getProtocolFamily(); //short  currentProtocolFamilyID = nextPdu.getProtocolFamily();
+
+                    StringBuilder message = new StringBuilder();
+                    message.append(DisTime.timeStampToString(nextPdu.getTimestamp())).append(" ");
+                    message.append("received new DIS PDU ");
+                    String currentPduTypePadded     = String.format("%-48s", currentPduType);     // - indicates right padding of whitespace
+                    message.append(currentPduTypePadded);
+                    // optional, verbose
+        //            String currentPduTypeNamePadded = String.format("%-49s", currentPduTypeName); // - indicates right padding of whitespace
+        //            message.append(" of type ").append(currentPduTypeNamePadded); // package.class name
+                    message.append(" (").append(currentProtocolFamilyID);
+        //          message.append(" ").append(currentPduFamilyName); // class name is also available
+                    message.append(")");
+                    System.out.println(message.toString()); // diagnostic information helps
+
+                    // additional message information of interest, if any
+                    switch (currentPduType) // using enumeration values from edu.​nps.​moves.​dis7.​enumerations.​DisPduType
                     {
-                        String nextComment = new String(variableDatum.getVariableDatumValue()); // convert byte[] to String
-                        System.out.print  (" \"" + nextComment + "\"");
+                        case COMMENT:
+                            CommentPdu commentPdu = (CommentPdu)nextPdu; // cast to precise type
+                            ArrayList<VariableDatum> payloadList = (ArrayList)commentPdu.getVariableDatums();
+                            if (!payloadList.isEmpty())
+                                System.out.print  ("   messages: ");
+                            for (VariableDatum variableDatum : payloadList)
+                            {
+                                String nextComment = new String(variableDatum.getVariableDatumValue()); // convert byte[] to String
+                                System.out.print  (" \"" + nextComment + "\"");
+                            }
+                            System.out.println();
                     }
-                    System.out.println();
+                }
+                pduBundle.clear();
             }
         }
-        pduBundle.clear();
+        catch (IOException e) {
+          System.out.println("Problem with OpenDis7Examples.AllPduReceiver, see exception trace:");
+          System.out.println(e);
+        }
+        finally {
+          System.out.println("OpenDis7Examples.AllPduReceiver complete.");
+        }
       }
-    }
-    catch (IOException e) {
-      System.out.println("Problem with OpenDis7Examples.AllPduReceiver, see exception trace:");
-      System.out.println(e);
-    }
-    finally {
-      System.out.println("OpenDis7Examples.AllPduReceiver complete.");
-    }
-  }
 }
diff --git a/examples/src/OpenDis7Examples/AllPduSender.java b/examples/src/OpenDis7Examples/AllPduSender.java
index aa4d339e6d..1485b3cba8 100755
--- a/examples/src/OpenDis7Examples/AllPduSender.java
+++ b/examples/src/OpenDis7Examples/AllPduSender.java
@@ -32,7 +32,7 @@ public class AllPduSender
      * Putting any upper limit on # packets sent avoids possibility of non-terminating infinite loops that continue sending packets. */
     private int                SEND_LOOPS_TO_PERFORM = 1;
     
-    private static InetAddress multicastAddress;
+    private static InetAddress multicastInetAddress;
     private static int         port;
 
     /** Object constructor
@@ -43,8 +43,8 @@ public class AllPduSender
         this.port = DEFAULT_MULTICAST_PORT;
         try
 		{
-            multicastAddress = InetAddress.getByName(newMulticastAddress);
-            if (!multicastAddress.isMulticastAddress())
+            multicastInetAddress = InetAddress.getByName(newMulticastAddress);
+            if (!multicastInetAddress.isMulticastAddress())
 			{
                 System.out.println("Not a multicast address: " + newMulticastAddress);
             }
@@ -453,13 +453,24 @@ public class AllPduSender
                 // Send the PDUs we created
                 System.out.println("Send the " + generatedPdusList.size() + " PDUs we created...");
 
-                InetAddress localMulticastAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS);
+                // =======================================================================
+                // prior appproach
+//                InetAddress localMulticastAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS);
+//                MulticastSocket multicastSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
+//                if (!localMulticastAddress.isMulticastAddress())
+//                {
+//                    throw new RuntimeException("*** Error: sending to multicast address, but destination address " + localMulticastAddress.toString() + "is not multicast");
+//                }
+//                multicastSocket.joinGroup(localMulticastAddress); // deprecated
+                // =======================================================================
+                // updated approach using NetworkInterface
+                NetworkInterface networkInterface = NetworkInterface.getByInetAddress(multicastInetAddress);
+                if (networkInterface != null)
+                    System.out.println("networkInterface=" + networkInterface.getDisplayName()); // typically null if loopback
+                SocketAddress localMulticastSocketAddress = new InetSocketAddress(multicastInetAddress, DEFAULT_MULTICAST_PORT);
                 MulticastSocket multicastSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
-                if (!localMulticastAddress.isMulticastAddress())
-                {
-                    throw new RuntimeException("*** Error: sending to multicast address, but destination address " + localMulticastAddress.toString() + "is not multicast");
-                }
-                multicastSocket.joinGroup(localMulticastAddress);
+                multicastSocket.joinGroup(localMulticastSocketAddress, networkInterface);
+                // =======================================================================
 
                 byte[] buffer;
                 Pdu aPdu;
@@ -477,7 +488,7 @@ public class AllPduSender
                         aPdu.marshal(dos); // dos is DataOutputStream connected to ByteArrayOutputStrea
 
                         buffer = baos.toByteArray();
-                        packet = new DatagramPacket(buffer, buffer.length, localMulticastAddress, DEFAULT_MULTICAST_PORT);
+                        packet = new DatagramPacket(buffer, buffer.length, multicastInetAddress, DEFAULT_MULTICAST_PORT);
                         multicastSocket.send(packet);
                         
                         DisPduType disPduType= aPdu.getPduType();
@@ -526,7 +537,7 @@ public class AllPduSender
         if (args.length == 2)
         {
             System.out.println("Usage:   AllPduSender <multicast group> <port>");
-            System.out.println("Actual:  AllPduSender  " + multicastAddress.getHostAddress() + "   " + port);
+            System.out.println("Actual:  AllPduSender  " + multicastInetAddress.getHostAddress() + "   " + port);
             allPduSender = new AllPduSender(args[0], Integer.parseInt(args[1]));
         } 
         else
-- 
GitLab