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..4c709d17f1 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,6 +253,8 @@ 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()) { @@ -260,7 +262,13 @@ private void checkHostnameAndCameraNames() { 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..6f63f22198 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,57 @@ 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 { - 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); - } - return ""; - } - try { - byte[] mac = NetworkInterface.getByName(config.networkManagerIface).getHardwareAddress(); - if (mac == null) { - logger.error("No MAC address found for " + config.networkManagerIface); - return ""; + // 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 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) {