Skip to content

Commit

Permalink
better support for instanceid generation in windows
Browse files Browse the repository at this point in the history
  • Loading branch information
tomtzook committed Nov 8, 2023
1 parent cfd9906 commit ddd13d5
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.flash3388.flashlib.net.util;
package com.flash3388.flashlib.util.net;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.NoSuchElementException;

public class NetInterfaces {
Expand Down Expand Up @@ -35,4 +36,21 @@ public static InterfaceAddress getIpv4AddressByInterface(NetworkInterface networ

throw new NoSuchElementException("address not found");
}

public static byte[] getMacAddress() throws IOException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
if (!interfaces.hasMoreElements()) {
throw new IOException("no network interfaces available");
}

while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
byte[] hardwareAddress = networkInterface.getHardwareAddress();
if (hardwareAddress != null) {
return hardwareAddress;
}
}

throw new IOException("unable to obtain hardware address");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

public class InstanceId {
private static final int PROCESS_ID_SIZE = Long.BYTES;
Expand All @@ -14,6 +15,9 @@ public class InstanceId {
private final byte[] mProcessId;

public InstanceId(byte[] machineId, byte[] processId) {
Objects.requireNonNull(machineId, "machineId");
Objects.requireNonNull(processId, "processId");

assert machineId.length > 1;
assert PROCESS_ID_SIZE == processId.length;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import com.castle.util.os.KnownOperatingSystem;
import com.flash3388.flashlib.util.Binary;
import com.flash3388.flashlib.util.logging.Logging;
import com.flash3388.flashlib.util.net.NetInterfaces;
import org.slf4j.Logger;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.NetworkInterface;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;

public class InstanceIdGenerator {

Expand All @@ -37,58 +40,98 @@ public static InstanceId generate() {

private static byte[] getMachineId() {
if (KnownOperatingSystem.LINUX.isCurrent()) {
Path machineIdFile = Paths.get("/etc/machine-id");
if (Files.exists(machineIdFile)) {
try {
LOGGER.debug("Using /etc/machine-id for machine-id");
byte[] id = Files.readAllBytes(machineIdFile);

MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(id);
return digest.digest();
} catch (IOException | NoSuchAlgorithmException e) {
// failed to get id from file
LOGGER.error("Failed retrieving machine id from /etc/machine-id", e);
}
Optional<byte[]> optional = getMachineIdLinux();
if (optional.isPresent()) {
return optional.get();
}
} else if (KnownOperatingSystem.WINDOWS.isCurrent()) {
Optional<byte[]> optional = getMachineIdWindows();
if (optional.isPresent()) {
return optional.get();
}
}

return getMachineIdFallback();
}

private static Optional<byte[]> getMachineIdLinux() {
Path machineIdFile = Paths.get("/etc/machine-id");
if (Files.exists(machineIdFile)) {
try {
LOGGER.debug("Using /etc/machine-id for machine-id");
byte[] id = Files.readAllBytes(machineIdFile);

MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(id);
byte[] result = digest.digest();
return Optional.of(result);
} catch (IOException | NoSuchAlgorithmException e) {
// failed to get id from file
LOGGER.error("Failed retrieving machine id from /etc/machine-id", e);
}
} else {
LOGGER.debug("/etc/machine-id does not exist");
}

return Optional.empty();
}

private static Optional<byte[]> getMachineIdWindows() {
try {
String serialNumber = Wmic.getBiosSerialNumber();
byte[] id = serialNumber.getBytes(StandardCharsets.UTF_8);
return Optional.of(id);
} catch (IOException e) {
LOGGER.error("Failed retrieving serial number from wmic", e);
}

return Optional.empty();
}

private static byte[] getMachineIdFallback() {
try {
// although not fool-proof, we'll use MAC address from the machine.
// MAC addresses can actually change, but for now this will do.
LOGGER.debug("Using MAC address for machine-id");
return getMacAddress();
return NetInterfaces.getMacAddress();
} catch (IOException e) {
throw new IdGenerationException("failed retrieving MAC address", e);
}
}

private static byte[] getMacAddress() throws IOException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
if (!interfaces.hasMoreElements()) {
throw new IOException("no network interfaces available");
private static long getPid() {
if (KnownOperatingSystem.LINUX.isCurrent()) {
Optional<Long> optionalPid = getPidLinux();
if (optionalPid.isPresent()) {
return optionalPid.get();
}
}

NetworkInterface networkInterface = interfaces.nextElement();
return networkInterface.getHardwareAddress();
return getPidFallback();
}

private static long getPid() {
if (KnownOperatingSystem.LINUX.isCurrent()) {
Path processStat = Paths.get("/proc/self/stat");
if (Files.exists(processStat)) {
try {
LOGGER.debug("Using /proc/self for process-id");
List<String> lines = Files.readAllLines(processStat);
String pidString = lines.get(0).split(" ")[0];
return Long.parseLong(pidString);
} catch (IOException | NumberFormatException e) {
// failed to get id from file
LOGGER.error("Failed retrieving machine id from /proc/self", e);
}
private static Optional<Long> getPidLinux() {
Path processStat = Paths.get("/proc/self/stat");
if (Files.exists(processStat)) {
try {
LOGGER.debug("Using /proc/self for process-id");

List<String> lines = Files.readAllLines(processStat);
String pidString = lines.get(0).split(" ")[0];
long pid = Long.parseLong(pidString);
return Optional.of(pid);
} catch (IOException | NumberFormatException e) {
// failed to get id from file
LOGGER.error("Failed retrieving machine id from /proc/self", e);
}
} else {
LOGGER.debug("/proc/self/stat does not exist");
}

return Optional.empty();
}

private static long getPidFallback() {
try {
LOGGER.debug("Using ManagementFactory.getRuntimeMXBean() for process-id");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.flash3388.flashlib.util.unique;

import com.castle.util.closeables.Closeables;

import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class Wmic {

private Wmic() {}

public static String getBiosSerialNumber() throws IOException {
return getWmicOutputLine(
new String[]{"bios", "get", "serialNumber"},
"SerialNumber");
}

public static String getWmicOutputLine(String[] cmd, String outputLine) throws IOException {
// https://stackoverflow.com/questions/1986732/how-to-get-a-unique-computer-identifier-in-java-like-disk-id-or-motherboard-id
String[] cmdFull = new String[cmd.length + 1];
cmdFull[0] = "wmic";
System.arraycopy(cmd, 0, cmdFull, 1, cmd.length);

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(cmdFull);
try {
process.getOutputStream().close();

InputStream procOutput = process.getInputStream();
try {
Scanner scanner = new Scanner(procOutput);
while (scanner.hasNext()) {
String text = scanner.next();
if (text.equals(outputLine)) {
if (!scanner.hasNext()) {
throw new IOException("found line, but proc output has reached its end");
}

return scanner.next();
}
}

throw new IOException("wanted line not found");
} finally {
Closeables.silentClose(procOutput);
}
} finally {
Closeables.silentClose(()-> {
if (process.isAlive()) {
process.destroyForcibly();
}
});
}
}
}

0 comments on commit ddd13d5

Please sign in to comment.