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);
}
}