Fix incorrect hostname on non-managed devices (#2203)

I have all sorts of weird adapters from npcap and Hyper-V that don't
have MAC addresses, so I'm simplifying the logic down so that it always
tries to find _any_ adapter with a MAC address, but attempts to see if
it can find what adapter is in use right now and use the MAC address
from that. This also unpublishes old MAC address topics, which wasn't
done before.
This commit is contained in:
Gold856
2025-12-12 01:40:34 -05:00
committed by GitHub
parent 9490c2f2cd
commit a585a1d339
2 changed files with 54 additions and 27 deletions

View File

@@ -253,6 +253,8 @@ public class NetworkTablesManager {
String mac = NetworkUtils.getMacAddress();
if (!mac.equals(currentMacAddress)) {
logger.debug("MAC address changed! New MAC address is " + mac + ", was " + currentMacAddress);
kCoprocTable.getSubTable(currentMacAddress).getEntry("hostname").unpublish();
kCoprocTable.getSubTable(currentMacAddress).getEntry("cameraNames").unpublish();
currentMacAddress = mac;
}
if (mac.isEmpty()) {
@@ -260,7 +262,13 @@ public class NetworkTablesManager {
return;
}
String hostname = ConfigManager.getInstance().getConfig().getNetworkConfig().hostname;
var config = ConfigManager.getInstance().getConfig();
String hostname;
if (config.getNetworkConfig().shouldManage) {
hostname = config.getNetworkConfig().hostname;
} else {
hostname = CameraServerJNI.getHostname();
}
if (hostname == null || hostname.isEmpty()) {
logger.error("Cannot check hostname and camera names, hostname is not set!");
return;

View File

@@ -17,7 +17,9 @@
package org.photonvision.common.networking;
import edu.wpi.first.networktables.NetworkTableInstance;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.List;
@@ -218,40 +220,57 @@ public class NetworkUtils {
return String.join(", ", addresses);
}
/**
* Gets a MAC address of a network interface. On devices where networking is managed by
* PhotonVision, this will return the MAC address of the configured interface. Otherwise, this
* will attempt to search for the network interface in current use and use that interface's MAC
* address, and if that fails, it will return a MAC address from the first network interface with
* a MAC address, as sorted by {@link NetworkInterface#networkInterfaces()}.
*
* @return The MAC address.
*/
public static String getMacAddress() {
var config = ConfigManager.getInstance().getConfig().getNetworkConfig();
if (config.networkManagerIface == null || config.networkManagerIface.isBlank()) {
// This is a silly heuristic to find a network interface that PV might be using. It looks like
// it works pretty well, but Hyper-V adapters still show up in the list. But we're using MAC
// address as a semi-unique identifier, not as a source of truth, so this should be fine.
// Hyper-V adapters seem to show up near the end of the list anyways, so it's super likely
// we'll find the right adapter anyways
try {
for (var iface : NetworkInterface.networkInterfaces().toList()) {
if (iface.isUp() && !iface.isVirtual() && !iface.isLoopback()) {
byte[] mac = iface.getHardwareAddress();
if (mac == null) {
logger.error("No MAC address found for " + iface.getDisplayName());
}
try {
// Not managed? See if we're connected to a network. General assumption is one interface in
// use at a time
if (config.networkManagerIface == null || config.networkManagerIface.isBlank()) {
// Use NT client IP address to find the interface in use
if (!config.runNTServer) {
var conn = NetworkTableInstance.getDefault().getConnections();
if (conn.length > 0 && !conn[0].remote_ip.equals("127.0.0.1")) {
var addr = InetAddress.getByName(conn[0].remote_ip);
return formatMacAddress(NetworkInterface.getByInetAddress(addr).getHardwareAddress());
}
}
// Connected to a localhost server or we are the server? Try resolving ourselves. Only
// returns a localhost address when there's no other interface available on Windows, but
// like to return a localhost address on Linux
var localIface = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
if (localIface != null) {
byte[] mac = localIface.getHardwareAddress();
if (mac != null) {
return formatMacAddress(mac);
}
}
} catch (Exception e) {
logger.error("Error getting MAC address:", e);
// Fine. Just find something with a MAC address
for (var iface : NetworkInterface.networkInterfaces().toList()) {
if (iface.isUp() && iface.getHardwareAddress() != null) {
return formatMacAddress(iface.getHardwareAddress());
}
}
} else { // Managed? We should have a working interface available
byte[] mac = NetworkInterface.getByName(config.networkManagerIface).getHardwareAddress();
if (mac != null) {
return formatMacAddress(mac);
} else {
logger.error("No MAC address found for " + config.networkManagerIface);
}
}
return "";
}
try {
byte[] mac = NetworkInterface.getByName(config.networkManagerIface).getHardwareAddress();
if (mac == null) {
logger.error("No MAC address found for " + config.networkManagerIface);
return "";
}
return formatMacAddress(mac);
} catch (Exception e) {
logger.error("Error getting MAC address for " + config.networkManagerIface, e);
return "";
logger.error("Error getting MAC address", e);
}
return "";
}
private static String formatMacAddress(byte[] mac) {