Coverage Summary for Class: InterfaceResolver (it.polimi.ingsw.gc14.Network)

Class Class, % Method, % Branch, % Line, %
InterfaceResolver 0% (0/1) 0% (0/3) 0% (0/26) 0% (0/22)


 package it.polimi.ingsw.gc14.Network;
 
 import java.net.*;
 import java.util.Enumeration;
 
 /** Utility class for resolving the local network interface to use when connecting to a server. */
 public class InterfaceResolver {
     private InterfaceResolver() {}
 
     /**
      * Returns the local IPv4 address that can reach the given server IP.
      *
      * <p>If the server is localhost, returns {@code "127.0.0.1"}.
      * Otherwise, iterates active non-loopback interfaces to find one on the same subnet;
      * falls back to a UDP connect trick if no matching subnet is found.
      *
      * @param serverIp the server IP address or hostname.
      * @return the local IP address string to use for outbound connections.
      * @throws Exception if no suitable interface can be determined.
      */
     public static String resolveLocalInterface(String serverIp) throws Exception {
         if (serverIp.equalsIgnoreCase("localhost") || serverIp.startsWith("127.") || serverIp.isEmpty()) {
             return "127.0.0.1";
         }
 
         InetAddress serverAddr = InetAddress.getByName(serverIp);
         Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
         while (ifaces.hasMoreElements()) {
             NetworkInterface ni = ifaces.nextElement();
             if (!ni.isUp() || ni.isLoopback()) continue;
 
             for (InterfaceAddress ia : ni.getInterfaceAddresses()) {
                 InetAddress localAddr = ia.getAddress();
                 if (!(localAddr instanceof Inet4Address)) continue;
 
                 int prefix = ia.getNetworkPrefixLength();
                 if (sameSubnet(localAddr, serverAddr, prefix)) {
                     return localAddr.getHostAddress();
                 }
             }
         }
 
         try (DatagramSocket socket = new DatagramSocket()) {
             socket.connect(serverAddr, 9);
             return socket.getLocalAddress().getHostAddress();
         }
     }
     /**
      * Returns {@code true} if {@code a} and {@code b} share the same subnet given a CIDR {@code prefix} length.
      *
      * @param a      first IPv4 address.
      * @param b      second IPv4 address.
      * @param prefix CIDR prefix length (0–32).
      * @return {@code true} if both addresses belong to the same subnet.
      */
     private static boolean sameSubnet(InetAddress a, InetAddress b, int prefix) {
         if (prefix < 0 || prefix > 32) return false;
         int maskBits = prefix == 0 ? 0 : (0xFFFFFFFF << (32 - prefix));
         int addrA = toInt(a.getAddress()) & maskBits;
         int addrB = toInt(b.getAddress()) & maskBits;
         return addrA == addrB;
     }
     /**
      * Converts a 4-byte big-endian IPv4 address array to a signed 32-bit integer.
      *
      * @param bytes the 4-byte address array.
      * @return the corresponding signed integer.
      */
     private static int toInt(byte[] bytes) {
         return ((bytes[0] & 0xFF) << 24) |
                 ((bytes[1] & 0xFF) << 16) |
                 ((bytes[2] & 0xFF) <<  8) |
                 (bytes[3] & 0xFF);
     }
 }