From bc3413e32d5d4e5e7f0be43c92421c43596fff8b Mon Sep 17 00:00:00 2001 From: Gold856 <117957790+Gold856@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:00:28 -0500 Subject: [PATCH] Improve MAC address detection and fix incorrect hostname on non-managed devices --- .../networktables/NetworkTablesManager.java | 12 +++- .../common/networking/NetworkUtils.java | 68 ++++++++++++------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java index a86cf51b18..c274555b4f 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java @@ -253,14 +253,22 @@ private void checkHostnameAndCameraNames() { 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()) { + if (mac.equals("00-00-00-00-00-00")) { logger.error("Cannot check hostname and camera names, MAC address is not set!"); 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; diff --git a/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java b/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java index 77aee6600a..8b05cb0828 100644 --- a/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java +++ b/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java @@ -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,54 @@ public static String getIPAddresses(String iFaceName) { 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 { + 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 + byte[] mac = + NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress(); + if (mac != null) { + return formatMacAddress(mac); + } + // Fine. Just find something with a MAC address 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()); - } - return formatMacAddress(mac); + if (iface.isUp() && iface.getHardwareAddress() != null) { + return formatMacAddress(iface.getHardwareAddress()); } } - } catch (Exception e) { - logger.error("Error getting MAC address:", e); - } - return ""; - } - try { - byte[] mac = NetworkInterface.getByName(config.networkManagerIface).getHardwareAddress(); - if (mac == null) { - logger.error("No MAC address found for " + config.networkManagerIface); - return ""; + } 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 formatMacAddress(mac); } catch (Exception e) { - logger.error("Error getting MAC address for " + config.networkManagerIface, e); - return ""; + logger.error("Error getting MAC address", e); } + return "00-00-00-00-00-00"; } private static String formatMacAddress(byte[] mac) {