diff --git a/AGENTS.md b/AGENTS.md
index 6c38205..70a2db6 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -26,7 +26,7 @@ Unit tests must not depend on a real BMC. Exercising the RMCP+ session code agai
## Code quality reports
-Code quality reports (checkstyle, pmd/cpd, spotbugs) are generated by `mvn verify site` into ./target/checkstyle-result.xml, ./target/pmd.xml, ./target/cpd.xml and ./target/spotbugsXml.xml. Checkstyle is gated (the build fails on any error); PMD/CPD and SpotBugs are not yet gated (issues #114, #115, #116 track the clean-up). Do not add new violations: check the reports for the files you changed before committing and submitting your code. On JDK 21+ the SpotBugs plugin version inherited from the parent POM cannot read the JDK class files; run `mvn com.github.spotbugs:spotbugs-maven-plugin:4.10.4.1:spotbugs` instead.
+Code quality reports (checkstyle, pmd/cpd, spotbugs) are generated by `mvn verify site` into ./target/checkstyle-result.xml, ./target/pmd.xml, ./target/cpd.xml and ./target/spotbugsXml.xml. Checkstyle and PMD are gated (the build fails on any error); CPD and SpotBugs are not yet gated (issues #115 and #116 track the clean-up). Do not add new violations: check the reports for the files you changed before committing and submitting your code. On JDK 21+ the SpotBugs plugin version inherited from the parent POM cannot read the JDK class files; run `mvn com.github.spotbugs:spotbugs-maven-plugin:4.10.4.1:spotbugs` instead.
## Documentation
diff --git a/pom.xml b/pom.xml
index e4a343f..5ae3b1a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -148,6 +148,27 @@
+
+
+ org.apache.maven.plugins
+ maven-pmd-plugin
+ 3.28.0
+
+ ${maven.compiler.release}
+
+ pmd.xml
+
+ true
+
+
+
+
+ check
+
+
+
+
+
org.codehaus.mojo
@@ -162,9 +183,10 @@
-
+
maven-pmd-plugin
+ 3.28.0
true
${project.build.sourceEncoding}
diff --git a/src/main/java/org/metricshub/ipmi/client/runner/AbstractIpmiRunner.java b/src/main/java/org/metricshub/ipmi/client/runner/AbstractIpmiRunner.java
index 9be79cc..6ab64ac 100644
--- a/src/main/java/org/metricshub/ipmi/client/runner/AbstractIpmiRunner.java
+++ b/src/main/java/org/metricshub/ipmi/client/runner/AbstractIpmiRunner.java
@@ -219,7 +219,7 @@ public void close() {
try {
connector.closeSession(handle);
} catch (Exception e) {
- // Ignore
+ LOGGER.debug("Failed to close the IPMI session", e);
}
}
diff --git a/src/main/java/org/metricshub/ipmi/client/runner/GetFrusRunner.java b/src/main/java/org/metricshub/ipmi/client/runner/GetFrusRunner.java
index 6260ac3..a5435ae 100644
--- a/src/main/java/org/metricshub/ipmi/client/runner/GetFrusRunner.java
+++ b/src/main/java/org/metricshub/ipmi/client/runner/GetFrusRunner.java
@@ -47,12 +47,16 @@
import org.metricshub.ipmi.core.coding.payload.CompletionCode;
import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Get FRU information
*/
public class GetFrusRunner extends AbstractIpmiRunner> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GetFrusRunner.class);
+
/**
* Id of the built-in, default FRU
*/
@@ -197,7 +201,7 @@ private void processFruRecord(
}
} catch (IPMIException e) {
- // Nothing can be done
+ LOGGER.warn("Failed to read the FRU of sensor record {}: {}", sensorRecord.getId(), e.getMessage());
}
}
@@ -249,7 +253,7 @@ private List getFruRecords(int fruId) throws Exception {
fruData.add(data);
} catch (Exception e) {
- // Nothing can be done
+ LOGGER.warn("Failed to read FRU {} at offset {}, the FRU data will be truncated: {}", fruId, i, e.getMessage());
}
}
@@ -265,7 +269,7 @@ private List getFruRecords(int fruId) throws Exception {
.collect(Collectors.toList());
} catch (Exception e) {
- // Nothing can be done
+ LOGGER.warn("Failed to decode FRU {}: {}", fruId, e.getMessage());
}
return new ArrayList<>();
diff --git a/src/main/java/org/metricshub/ipmi/core/api/async/IpmiAsyncConnector.java b/src/main/java/org/metricshub/ipmi/core/api/async/IpmiAsyncConnector.java
index ebd78a2..8f6b631 100644
--- a/src/main/java/org/metricshub/ipmi/core/api/async/IpmiAsyncConnector.java
+++ b/src/main/java/org/metricshub/ipmi/core/api/async/IpmiAsyncConnector.java
@@ -388,7 +388,6 @@ public void closeSession(ConnectionHandle connectionHandle)
}
}
}
- return;
}
/**
diff --git a/src/main/java/org/metricshub/ipmi/core/api/sol/SerialOverLan.java b/src/main/java/org/metricshub/ipmi/core/api/sol/SerialOverLan.java
index cce09f3..5344be6 100644
--- a/src/main/java/org/metricshub/ipmi/core/api/sol/SerialOverLan.java
+++ b/src/main/java/org/metricshub/ipmi/core/api/sol/SerialOverLan.java
@@ -611,7 +611,12 @@ private void waitForData(int wantedByteCount, int timeout) {
long startTime = System.currentTimeMillis();
while (isTooFewBytesAvailable(wantedByteCount) && timeoutNotHit(timeout, startTime)) {
- // NOP, just waiting
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
+ }
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/DecoderRunner.java b/src/main/java/org/metricshub/ipmi/core/coding/DecoderRunner.java
deleted file mode 100644
index 3c4f5b1..0000000
--- a/src/main/java/org/metricshub/ipmi/core/coding/DecoderRunner.java
+++ /dev/null
@@ -1,1321 +0,0 @@
-package org.metricshub.ipmi.core.coding;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * IPMI Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 Verax Systems, MetricsHub
- * ჻჻჻჻჻჻
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Lesser Public License for more details.
- *
- * You should have received a copy of the GNU General Lesser Public
- * License along with this program. If not, see
- * .
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import org.metricshub.ipmi.core.coding.commands.IpmiVersion;
-import org.metricshub.ipmi.core.coding.commands.PrivilegeLevel;
-import org.metricshub.ipmi.core.coding.commands.chassis.GetChassisStatus;
-import org.metricshub.ipmi.core.coding.commands.chassis.GetChassisStatusResponseData;
-import org.metricshub.ipmi.core.coding.commands.fru.BaseUnit;
-import org.metricshub.ipmi.core.coding.commands.fru.GetFruInventoryAreaInfo;
-import org.metricshub.ipmi.core.coding.commands.fru.GetFruInventoryAreaInfoResponseData;
-import org.metricshub.ipmi.core.coding.commands.fru.ReadFruData;
-import org.metricshub.ipmi.core.coding.commands.fru.ReadFruDataResponseData;
-import org.metricshub.ipmi.core.coding.commands.fru.record.BoardInfo;
-import org.metricshub.ipmi.core.coding.commands.fru.record.ChassisInfo;
-import org.metricshub.ipmi.core.coding.commands.fru.record.FruRecord;
-import org.metricshub.ipmi.core.coding.commands.fru.record.ProductInfo;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSdr;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSdrRepositoryInfo;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSdrRepositoryInfoResponseData;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSdrResponseData;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSensorReading;
-import org.metricshub.ipmi.core.coding.commands.sdr.GetSensorReadingResponseData;
-import org.metricshub.ipmi.core.coding.commands.sdr.ReserveSdrRepository;
-import org.metricshub.ipmi.core.coding.commands.sdr.ReserveSdrRepositoryResponseData;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.CompactSensorRecord;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.FruDeviceLocatorRecord;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.FullSensorRecord;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.RateUnit;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.ReadingType;
-import org.metricshub.ipmi.core.coding.commands.sdr.record.SensorRecord;
-import org.metricshub.ipmi.core.coding.commands.sel.GetSelEntry;
-import org.metricshub.ipmi.core.coding.commands.sel.GetSelEntryResponseData;
-import org.metricshub.ipmi.core.coding.commands.sel.GetSelInfo;
-import org.metricshub.ipmi.core.coding.commands.sel.GetSelInfoResponseData;
-import org.metricshub.ipmi.core.coding.commands.sel.ReserveSel;
-import org.metricshub.ipmi.core.coding.commands.sel.ReserveSelResponseData;
-import org.metricshub.ipmi.core.coding.commands.sel.SelRecord;
-import org.metricshub.ipmi.core.coding.commands.session.CloseSession;
-import org.metricshub.ipmi.core.coding.commands.session.GetChannelAuthenticationCapabilities;
-import org.metricshub.ipmi.core.coding.commands.session.GetChannelAuthenticationCapabilitiesResponseData;
-import org.metricshub.ipmi.core.coding.commands.session.GetChannelCipherSuites;
-import org.metricshub.ipmi.core.coding.commands.session.GetChannelCipherSuitesResponseData;
-import org.metricshub.ipmi.core.coding.commands.session.OpenSession;
-import org.metricshub.ipmi.core.coding.commands.session.OpenSessionResponseData;
-import org.metricshub.ipmi.core.coding.commands.session.Rakp1;
-import org.metricshub.ipmi.core.coding.commands.session.Rakp1ResponseData;
-import org.metricshub.ipmi.core.coding.commands.session.Rakp3;
-import org.metricshub.ipmi.core.coding.commands.session.Rakp3ResponseData;
-import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
-import org.metricshub.ipmi.core.coding.protocol.decoder.PlainCommandv20Decoder;
-import org.metricshub.ipmi.core.coding.protocol.decoder.Protocolv15Decoder;
-import org.metricshub.ipmi.core.coding.protocol.decoder.Protocolv20Decoder;
-import org.metricshub.ipmi.core.coding.protocol.encoder.Protocolv15Encoder;
-import org.metricshub.ipmi.core.coding.protocol.encoder.Protocolv20Encoder;
-import org.metricshub.ipmi.core.coding.security.CipherSuite;
-import org.metricshub.ipmi.core.coding.security.SecurityConstants;
-import org.metricshub.ipmi.core.common.TypeConverter;
-
-import javax.crypto.NoSuchPaddingException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Test driver for Encoder/Decoder
- */
-public class DecoderRunner extends Thread {
-
- private DatagramSocket socket;
-
- private static int managedSeqNum;
- private static boolean lock;
-
- private static Rakp1 r1;
- private static Rakp1ResponseData r1rd;
- private static CipherSuite cs = new CipherSuite(
- (byte) 0,
- SecurityConstants.AA_RAKP_HMAC_SHA1,
- (byte) 0,
- (byte) 0);
-
- private static Logger logger = LoggerFactory.getLogger(DecoderRunner.class);
-
- private static int cssrcv = 16;
-
- private static int reservation;
-
- private static int nextRecId = 0;
-
- private static byte[] cssrec;
-
- private static int fruId = 0;
-
- private static int fruSize = 528;
-
- public static void main(String[] args)
- throws IOException,
- InterruptedException,
- NoSuchAlgorithmException,
- InvalidKeyException {
-
- logger
- .info(
- DateFormat
- .getInstance()
- .format(
- new Date(new Date().getTime())));
-
- lock = true;
-
- DecoderRunner dr = new DecoderRunner();
-
- dr.socket = new DatagramSocket(6666);
-
- dr.start();
-
- Properties properties = new Properties();
- properties.load(new FileInputStream("src/test/resources/test.properties"));
-
- Thread.sleep(100);
-
- InetAddress ad = InetAddress.getByName((String) properties.get("testIp"));
-
- byte index = 0;
-
- while (cssrcv >= 16) {
-
- Thread.sleep(300);
-
- lock = true;
-
- byte[] outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetChannelCipherSuites(
- TypeConverter.intToByte(0xE),
- index),
- 0,
- 0,
- 0);
-
- ++index;
- DatagramPacket packet = new DatagramPacket(
- outmsg,
- outmsg.length,
- ad,
- 0x26F);
-
- dr.socket.send(packet);
-
- while (lock) {
- Thread.sleep(1);
- }
- }
-
- List csl = CipherSuite.getCipherSuites(cssrec);
-
- for (CipherSuite c : csl) {
- try {
- logger
- .info(
- c.getId() + ": "
- + c.getAuthenticationAlgorithm().getCode() + " "
- + c.getIntegrityAlgorithm().getCode() + " "
- + c.getConfidentialityAlgorithm().getCode());
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
-
- cs = csl.get(2);
-
- Thread.sleep(300);
-
- byte[] outmsg = Encoder
- .encode(
- new Protocolv15Encoder(),
- new GetChannelAuthenticationCapabilities(
- IpmiVersion.V15,
- IpmiVersion.V20,
- cs,
- PrivilegeLevel.User,
- TypeConverter.intToByte(14)),
- 0,
- 0,
- 0);
-
- DatagramPacket packet = new DatagramPacket(
- outmsg,
- outmsg.length,
- ad,
- 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(150);
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new OpenSession(
- 44,
- PrivilegeLevel.MaximumAvailable,
- cs),
- 0,
- 0,
- 0);
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(300);
-
- while (lock) {
- Thread.sleep(1);
- }
-
- lock = true;
-
- r1 = new Rakp1(
- managedSeqNum,
- PrivilegeLevel.User,
- (String) properties.get("username"),
- (String) properties.get("password"),
- null,
- cs);
-
- outmsg = Encoder.encode(new Protocolv20Encoder(), r1, 1, 1, 0);
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(150);
-
- while (lock) {
- Thread.sleep(1);
- }
-
- try {
- cs.initializeAlgorithms(r1.calculateSik(r1rd));
- } catch (NoSuchPaddingException e) {
- logger.error(e.getMessage(), e);
- }
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new Rakp3(
- (byte) 0,
- managedSeqNum,
- cs,
- r1,
- r1rd),
- 1,
- 1,
- 0);
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(150);
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetChassisStatus(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus),
- 1,
- 1,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(300);
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetSdrRepositoryInfo(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus),
- 2,
- 2,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
- Thread.sleep(300);
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new ReserveSdrRepository(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus),
- 3,
- 3,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- int seq = 4;
-
- lock = true;
-
- while (lock) {
- Thread.sleep(1);
- }
-
- while (nextRecId < 65535) {
-
- Thread.sleep(200);
-
- logger.info(">>Sending request for record " + nextRecId);
-
- int sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetSdr(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- reservation,
- nextRecId),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
- lock = true;
-
- while (lock) {
- Thread.sleep(1);
- }
-
- if (nextRecId > 0) {
- logger.info(">>Sending request for reading " + nextRecId);
-
- sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetSensorReading(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- nextRecId),
- sequence,
- sequence,
- r1.getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- lock = true;
-
- while (lock && nextRecId < 65535) {
- Thread.sleep(1);
- }
- }
-
- }
-
- nextRecId = 0;
-
- Thread.sleep(300);
-
- logger.info(">>Sending GetSelInfo");
-
- int sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetSelInfo(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(300);
-
- logger.info(">>Sending Reserve SEL");
-
- sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new ReserveSel(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- lock = true;
-
- while (lock) {
- Thread.sleep(1);
- }
-
- while (nextRecId < 65535) {
-
- Thread.sleep(200);
-
- logger.info(">>Sending request for SEL record " + nextRecId);
-
- sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetSelEntry(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- reservation,
- nextRecId),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
- lock = true;
-
- while (lock) {
- Thread.sleep(1);
- }
- }
-
- Thread.sleep(300);
-
- logger.info(">>Sending GetFruInventoryAreaInfo");
-
- sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new GetFruInventoryAreaInfo(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- fruId),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- for (int i = 0; i < fruSize; i += 100) {
-
- Thread.sleep(300);
-
- logger.info(">>Sending ReadFruData");
-
- int cnt = 100;
- if (i + cnt > fruSize) {
- cnt = fruSize % 100;
- }
-
- sequence = seq++;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new ReadFruData(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- fruId,
- BaseUnit.Bytes,
- i,
- cnt),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- }
-
- Thread.sleep(300);
-
- sequence = seq + 1;
-
- outmsg = Encoder
- .encode(
- new Protocolv20Encoder(),
- new CloseSession(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- r1
- .getManagedSystemSessionId()),
- sequence,
- sequence,
- r1
- .getManagedSystemSessionId());
-
- packet = new DatagramPacket(outmsg, outmsg.length, ad, 0x26F);
-
- dr.socket.send(packet);
-
- Thread.sleep(1000);
-
- dr.socket.close();
-
- }
-
- @Override
- public void run() {
-
- super.run();
-
- cssrec = new byte[0];
-
- byte[] buffer = null;
-
- while (cssrcv >= 16) {
- DatagramPacket resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetChannelCipherSuitesResponseData data = null;
-
- try {
- data = (GetChannelCipherSuitesResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(CipherSuite.getEmpty()),
- new GetChannelCipherSuites());
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- if (data != null && data.getCipherSuiteData() != null) {
- cssrcv = data.getCipherSuiteData().length;
-
- logger.info("{}", data.getCipherSuiteData().length);
-
- byte[] temp = new byte[cssrec.length + cssrcv];
-
- System.arraycopy(cssrec, 0, temp, 0, cssrec.length);
- System
- .arraycopy(
- data.getCipherSuiteData(),
- 0,
- temp,
- cssrec.length,
- cssrcv);
- cssrec = temp;
-
- } else {
- cssrcv = 0;
- logger.info("{}", 0);
- }
-
- lock = false;
- }
-
- DatagramPacket resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetChannelAuthenticationCapabilitiesResponseData data = null;
-
- try {
- data = (GetChannelAuthenticationCapabilitiesResponseData) Decoder
- .decode(
- buffer,
- new Protocolv15Decoder(),
- new GetChannelAuthenticationCapabilities(
- IpmiVersion.V15,
- IpmiVersion.V20,
- cs));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("---------------------------------------------");
-
- logger.info("{}", data.getChannelNumber());
- logger.info("{}", data.isIpmiv20Support());
- logger.info("{}", data.getAuthenticationTypes().toString());
- logger.info("{}", data.isKgEnabled());
- logger.info("{}", data.isPerMessageAuthenticationEnabled());
- logger.info("{}", data.isUserLevelAuthenticationEnabled());
- logger.info("{}", data.isNonNullUsernamesEnabled());
- logger.info("{}", data.isNullUsernamesEnabled());
- logger.info("{}", data.isAnonymusLoginEnabled());
- logger.info("{}", data.getOemId());
- logger.info("{}", data.getOemData());
-
- logger.info("##############################################");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- logger.info(">>>> " + resp.getLength());
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- OpenSessionResponseData data2 = null;
-
- try {
- data2 = (OpenSessionResponseData) Decoder
- .decode(
- buffer,
- new PlainCommandv20Decoder(CipherSuite.getEmpty()),
- new OpenSession(CipherSuite.getEmpty()));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data2.getMessageTag());
- logger.info("{}", data2.getStatusCode());
- logger.info("{}", data2.getPrivilegeLevel());
- logger.info("{}", data2.getRemoteConsoleSessionId());
- logger.info("{}", data2.getManagedSystemSessionId());
- logger.info("{}", data2.getAuthenticationAlgorithm());
- logger.info("{}", data2.getConfidentialityAlgorithm());
- logger.info("{}", data2.getIntegrityAlgorithm());
-
- managedSeqNum = data2.getManagedSystemSessionId();
- lock = false;
-
- logger.info("---------------------------------------------");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- Rakp1ResponseData data3 = null;
-
- try {
- data3 = (Rakp1ResponseData) Decoder
- .decode(
- buffer,
- new PlainCommandv20Decoder(CipherSuite.getEmpty()),
- r1);
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- r1rd = data3;
-
- logger.info("{}", data3.getMessageTag());
- logger.info("{}", data3.getStatusCode());
- logger.info("{}", data3.getRemoteConsoleSessionId());
- logger.info("{}", data3.getManagedSystemGuid());
-
- logger.info("---------------------------------------------");
- lock = false;
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- Rakp3ResponseData data4 = null;
-
- try {
- data4 = (Rakp3ResponseData) Decoder
- .decode(
- buffer,
- new PlainCommandv20Decoder(CipherSuite.getEmpty()),
- new Rakp3(cs, r1, r1rd));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data4.getMessageTag());
- logger.info("{}", data4.getStatusCode());
- logger.info("{}", data4.getConsoleSessionId());
-
- logger.info("---------------------------------------------");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetChassisStatusResponseData data5 = null;
-
- try {
- data5 = (GetChassisStatusResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetChassisStatus(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data5.getPowerRestorePolicy());
- logger.info("{}", data5.isPowerControlFault());
- logger.info("{}", data5.isPowerFault());
- logger.info("{}", data5.isInterlock());
- logger.info("{}", data5.isPowerOverload());
- logger.info("{}", data5.isPowerOn());
-
- logger.info("________");
-
- logger.info("{}", data5.wasIpmiPowerOn());
- logger.info("{}", data5.wasPowerFault());
- logger.info("{}", data5.wasInterlock());
- logger.info("{}", data5.wasPowerOverload());
-
- logger.info("________");
-
- logger.info("{}", data5.isChassisIdentifyCommandSupported());
- if (data5.isChassisIdentifyCommandSupported()) {
- logger.info("{}", data5.getChassisIdentifyState());
- }
- logger.info("{}", data5.coolingFaultDetected());
- logger.info("{}", data5.driveFaultDetected());
- logger.info("{}", data5.isFrontPanelLockoutActive());
- logger.info("{}", data5.isChassisIntrusionActive());
-
- logger.info("________");
-
- logger.info("{}", data5.isFrontPanelButtonCapabilitiesSet());
-
- if (data5.isFrontPanelButtonCapabilitiesSet()) {
- try {
- logger.info("{}", data5.isStandbyButtonDisableAllowed());
- logger
- .info(
- "{}",
- data5
- .isDiagnosticInterruptButtonDisableAllowed());
- logger.info("{}", data5.isResetButtonDisableAllowed());
- logger.info("{}", data5.isPowerOffButtonDisableAllowed());
- logger.info("{}", data5.isStandbyButtonDisabled());
- logger.info("{}", data5.isDiagnosticInterruptButtonDisabled());
- logger.info("{}", data5.isResetButtonDisabled());
- logger.info("{}", data5.isPowerOffButtonDisabled());
- } catch (IllegalAccessException e) {
- logger.error(e.getMessage(), e);
- }
-
- }
-
- logger.info("---------------------------------------------");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetSdrRepositoryInfoResponseData data6 = null;
-
- try {
- data6 = (GetSdrRepositoryInfoResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetSdrRepositoryInfo(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data6.getSdrVersion());
- logger.info("{}", data6.getRecordCount());
- logger.info("{}", data6.getAddTimestamp());
- logger.info("{}", data6.getDelTimestamp());
- logger.info("{}", data6.isReserveSupported());
-
- logger.info("---------------------------------------------");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- ReserveSdrRepositoryResponseData data7 = null;
-
- try {
- data7 = (ReserveSdrRepositoryResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new ReserveSdrRepository(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data7.getReservationId());
-
- reservation = data7.getReservationId();
-
- logger.info("< 0) {
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System
- .arraycopy(
- resp.getData(),
- 0,
- buffer,
- 0,
- buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
- GetSensorReadingResponseData data9 = null;
-
- try {
- data9 = (GetSensorReadingResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetSensorReading(IpmiVersion.V20, cs, AuthenticationType.RMCPPlus, 0));
-
- if (record instanceof FullSensorRecord) {
- FullSensorRecord rec = (FullSensorRecord) record;
- logger
- .info(
- data9.getSensorReading(rec)
- + " "
- + rec.getSensorBaseUnit().toString()
- + (rec.getRateUnit() != RateUnit.None ?
- " per "
- + rec.getRateUnit() :
- ""));
- }
- if (record instanceof CompactSensorRecord) {
- CompactSensorRecord rec = (CompactSensorRecord) record;
- List events = data9
- .getStatesAsserted(
- rec.getSensorType(),
- rec.getEventReadingType());
- StringBuilder s = new StringBuilder();
- for (int i = 0; i < events.size(); ++i) {
- s.append(events.get(i)).append(", ");
- }
- logger.info(s.toString());
-
- }
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
-
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- logger.error(e.getMessage(), e);
- }
-
- nextRecId = data8.getNextRecordId();
-
- logger.info("---------------------------------------------");
-
- lock = false;
- }
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetSelInfoResponseData data10 = null;
-
- try {
- data10 = (GetSelInfoResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetSelInfo(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data10.getSelVersion());
- logger.info("{}", data10.getEntriesCount());
- logger
- .info(
- DateFormat
- .getInstance()
- .format(
- data10.getAdditionTimestamp()));
- logger
- .info(
- DateFormat
- .getInstance()
- .format(
- data10.getEraseTimestamp()));
-
- logger.info("---------------------------------------------");
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- ReserveSelResponseData data11 = null;
-
- try {
- data11 = (ReserveSelResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new ReserveSel(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info("{}", data11.getReservationId());
-
- reservation = data11.getReservationId();
- reservation = 0;
-
- lock = false;
-
- logger.info("---------------------------------------------");
-
- while (nextRecId < 65535) {
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
- GetSelEntryResponseData data12 = null;
-
- try {
- data12 = (GetSelEntryResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetSelEntry(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- 0,
- 0));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger.info(data12.getSelRecord().toString());
-
- SelRecord rec = data12.getSelRecord();
-
- logger.info("Sensor: " + rec.getSensorType());
- logger.info("{}", rec.getTimestamp());
- logger.info("{}", rec.getEventDirection());
- logger.info("{}", rec.getEvent());
-
- nextRecId = data12.getNextRecordId();
-
- lock = false;
-
- logger.info("---------------------------------------------");
- }
-
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- GetFruInventoryAreaInfoResponseData data13 = null;
-
- try {
- data13 = (GetFruInventoryAreaInfoResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new GetFruInventoryAreaInfo(IpmiVersion.V20, cs, AuthenticationType.RMCPPlus, 0));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- logger
- .info(
- "FRU inventory area size: "
- + data13.getFruInventoryAreaSize());
-
- logger.info("FRU Unit: " + data13.getFruUnit());
-
- logger.info("---------------------------------------------");
-
- List rd = new ArrayList();
-
- for (int i = 0; i < fruSize; i += 100) {
- resp = new DatagramPacket(new byte[256], 256);
-
- try {
- socket.receive(resp);
- buffer = new byte[resp.getLength()];
- System.arraycopy(resp.getData(), 0, buffer, 0, buffer.length);
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
-
- ReadFruDataResponseData data14 = null;
-
- try {
- data14 = (ReadFruDataResponseData) Decoder
- .decode(
- buffer,
- new Protocolv20Decoder(cs),
- new ReadFruData(
- IpmiVersion.V20,
- cs,
- AuthenticationType.RMCPPlus,
- 0,
- BaseUnit.Bytes,
- 0,
- 0));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
-
- rd.add(data14);
-
- logger.info("{}", data14.getFruData().length);
-
- logger.info("---------------------------------------------");
-
- }
-
- List records = ReadFruData.decodeFruData(rd);
-
- for (FruRecord r : records) {
- if (r instanceof ChassisInfo) {
- ChassisInfo chassisInfo = (ChassisInfo) r;
- logger.info("Chassis info:");
- logger.info("Chassis type: " + chassisInfo.getChassisType());
- logger.info("Chassis part number: " + chassisInfo.getChassisPartNumber());
- logger.info("Chassis serial number: " + chassisInfo.getChassisSerialNumber());
- for (String info : chassisInfo.getCustomChassisInfo()) {
- logger.info("Custom chassis info: " + info);
- }
- logger.info("---------------------------------------------");
- } else if (r instanceof BoardInfo) {
- BoardInfo boardInfo = (BoardInfo) r;
- logger.info("Board info:");
- logger.info("Board MFG date: " + boardInfo.getMfgDate().toString());
- logger.info("Board manufacturer: " + boardInfo.getBoardManufacturer());
- logger.info("Board product name: " + boardInfo.getBoardProductName());
- logger.info("Board part number: " + boardInfo.getBoardPartNumber());
- logger.info("Board serial number: " + boardInfo.getBoardSerialNumber());
- for (String info : boardInfo.getCustomBoardInfo()) {
- logger.info("Custom board info: " + info);
- }
- logger.info("---------------------------------------------");
- } else if (r instanceof ProductInfo) {
- ProductInfo productInfo = (ProductInfo) r;
- logger.info("Product info:");
- logger.info("Product manufacturer: " + productInfo.getManufacturerName());
- logger.info("Product product name: " + productInfo.getProductName());
- logger.info("Product part number: " + productInfo.getProductModelNumber());
- logger.info("Product version: " + productInfo.getProductVersion());
- logger.info("Product serial number: " + productInfo.getProductSerialNumber());
- logger.info("Product asset tag: " + productInfo.getAssetTag());
- for (String info : productInfo.getCustomProductInfo()) {
- logger.info("Custom board info: " + info);
- }
- logger.info("---------------------------------------------");
- }
- }
- }
-}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/chassis/GetChassisStatusResponseData.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/chassis/GetChassisStatusResponseData.java
index 986a50a..271226d 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/chassis/GetChassisStatusResponseData.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/chassis/GetChassisStatusResponseData.java
@@ -72,14 +72,14 @@ public PowerRestorePolicy getPowerRestorePolicy() {
* but system did not enter desired state
*/
public boolean isPowerControlFault() {
- return ((currentPowerState & TypeConverter.intToByte(0x10)) != 0);
+ return (currentPowerState & TypeConverter.intToByte(0x10)) != 0;
}
/**
* @return True when fault was detected in main power subsystem.
*/
public boolean isPowerFault() {
- return ((currentPowerState & TypeConverter.intToByte(0x8)) != 0);
+ return (currentPowerState & TypeConverter.intToByte(0x8)) != 0;
}
/**
@@ -87,7 +87,7 @@ public boolean isPowerFault() {
* because a chassis panel interlock switch is active)
*/
public boolean isInterlock() {
- return ((currentPowerState & TypeConverter.intToByte(0x4)) != 0);
+ return (currentPowerState & TypeConverter.intToByte(0x4)) != 0;
}
/**
@@ -95,14 +95,14 @@ public boolean isInterlock() {
* condition.
*/
public boolean isPowerOverload() {
- return ((currentPowerState & TypeConverter.intToByte(0x2)) != 0);
+ return (currentPowerState & TypeConverter.intToByte(0x2)) != 0;
}
/**
* @return True when system power is on.
*/
public boolean isPowerOn() {
- return ((currentPowerState & TypeConverter.intToByte(0x1)) != 0);
+ return (currentPowerState & TypeConverter.intToByte(0x1)) != 0;
}
public void setLastPowerEvent(byte lastPowerEvent) {
@@ -117,14 +117,14 @@ public byte getLastPowerEvent() {
* @return True when last 'Power is on' state was entered via IPMI command.
*/
public boolean wasIpmiPowerOn() {
- return ((lastPowerEvent & TypeConverter.intToByte(0x10)) != 0);
+ return (lastPowerEvent & TypeConverter.intToByte(0x10)) != 0;
}
/**
* @return True if last power down caused by power fault.
*/
public boolean wasPowerFault() {
- return ((lastPowerEvent & TypeConverter.intToByte(0x8)) != 0);
+ return (lastPowerEvent & TypeConverter.intToByte(0x8)) != 0;
}
/**
@@ -132,21 +132,21 @@ public boolean wasPowerFault() {
* activated.
*/
public boolean wasInterlock() {
- return ((lastPowerEvent & TypeConverter.intToByte(0x4)) != 0);
+ return (lastPowerEvent & TypeConverter.intToByte(0x4)) != 0;
}
/**
* @return True if last power down caused by a Power overload.
*/
public boolean wasPowerOverload() {
- return ((lastPowerEvent & TypeConverter.intToByte(0x2)) != 0);
+ return (lastPowerEvent & TypeConverter.intToByte(0x2)) != 0;
}
/**
* @return True if AC failed.
*/
public boolean acFailed() {
- return ((lastPowerEvent & TypeConverter.intToByte(0x1)) != 0);
+ return (lastPowerEvent & TypeConverter.intToByte(0x1)) != 0;
}
@@ -162,7 +162,7 @@ public byte getMiscChassisState() {
* @return True if Chassis Identify command and state info supported.
*/
public boolean isChassisIdentifyCommandSupported() {
- return ((miscChassisState & TypeConverter.intToByte(0x40)) != 0);
+ return (miscChassisState & TypeConverter.intToByte(0x40)) != 0;
}
public ChassisIdentifyState getChassisIdentifyState() {
@@ -182,14 +182,14 @@ public ChassisIdentifyState getChassisIdentifyState() {
* @return True if cooling or fan fault was detected.
*/
public boolean coolingFaultDetected() {
- return ((miscChassisState & TypeConverter.intToByte(0x8)) != 0);
+ return (miscChassisState & TypeConverter.intToByte(0x8)) != 0;
}
/**
* @return True if drive fault was detected.
*/
public boolean driveFaultDetected() {
- return ((miscChassisState & TypeConverter.intToByte(0x4)) != 0);
+ return (miscChassisState & TypeConverter.intToByte(0x4)) != 0;
}
/**
@@ -197,14 +197,14 @@ public boolean driveFaultDetected() {
* chassis push-buttons disabled.).
*/
public boolean isFrontPanelLockoutActive() {
- return ((miscChassisState & TypeConverter.intToByte(0x2)) != 0);
+ return (miscChassisState & TypeConverter.intToByte(0x2)) != 0;
}
/**
* @return True if Chassis intrusion active is active.
*/
public boolean isChassisIntrusionActive() {
- return ((miscChassisState & TypeConverter.intToByte(0x1)) != 0);
+ return (miscChassisState & TypeConverter.intToByte(0x1)) != 0;
}
public void setFrontPanelButtonCapabilities(
@@ -227,7 +227,7 @@ public boolean isStandbyButtonDisableAllowed()
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x80)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x80)) != 0;
}
/**
@@ -240,7 +240,7 @@ public boolean isDiagnosticInterruptButtonDisableAllowed()
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x40)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x40)) != 0;
}
/**
@@ -252,7 +252,7 @@ public boolean isResetButtonDisableAllowed() throws IllegalAccessException {
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x20)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x20)) != 0;
}
/**
@@ -267,7 +267,7 @@ public boolean isPowerOffButtonDisableAllowed()
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x10)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x10)) != 0;
}
/**
@@ -279,7 +279,7 @@ public boolean isStandbyButtonDisabled() throws IllegalAccessException {
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x8)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x8)) != 0;
}
/**
@@ -292,7 +292,7 @@ public boolean isDiagnosticInterruptButtonDisabled()
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x4)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x4)) != 0;
}
/**
@@ -304,7 +304,7 @@ public boolean isResetButtonDisabled() throws IllegalAccessException {
if (!isFrontPanelButtonCapabilitiesSet()) {
throw new IllegalAccessException(FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x2)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x2)) != 0;
}
/**
@@ -319,7 +319,7 @@ public boolean isPowerOffButtonDisabled() throws IllegalAccessException {
throw new IllegalAccessException(
FRONT_PANEL_BUTTON_CAPABILITIES_NOT_SET_MESSAGE);
}
- return ((frontPanelButtonCapabilities & TypeConverter.intToByte(0x1)) != 0);
+ return (frontPanelButtonCapabilities & TypeConverter.intToByte(0x1)) != 0;
}
private void setFrontPanelButtonCapabilitiesSet(
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/ReadFruData.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/ReadFruData.java
index b2e6a89..7601e18 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/ReadFruData.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/ReadFruData.java
@@ -263,9 +263,8 @@ public static List decodeFruData(
if (multiRecordOffset != 0) {
addMultirecords(list, data, multiRecordOffset);
}
- } else if (false) {
- // TODO: Recognize SPD record (returned from DIMM FRUs)
} else {
+ // TODO: recognize SPD records returned by DIMM FRUs (#107)
throw new IllegalArgumentException("Invalid format version: " + data[0]);
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/BoardInfo.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/BoardInfo.java
index 7d630d7..0f2756b 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/BoardInfo.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/BoardInfo.java
@@ -119,7 +119,7 @@ private ArrayList readCustomInfo(
int partType = (currentPartNumber & 0xc0) >> 6;
- int partDataLength = (currentPartNumber & 0x3f);
+ int partDataLength = currentPartNumber & 0x3f;
if (partDataLengthWithinBounds(fruData, currentOffset, partDataLength)) {
@@ -138,38 +138,34 @@ private ArrayList readCustomInfo(
switch (index) {
case 0:
setBoardManufacturer(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- languageCode != 0
- && languageCode != 25));
+ decodeString(
+ partType,
+ partNumberData,
+ languageCode != 0
+ && languageCode != 25));
break;
case 1:
setBoardProductName(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- languageCode != 0
- && languageCode != 25));
+ decodeString(
+ partType,
+ partNumberData,
+ languageCode != 0
+ && languageCode != 25));
break;
case 2:
setBoardSerialNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- true));
+ decodeString(
+ partType,
+ partNumberData,
+ true));
break;
case 3:
setBoardPartNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- languageCode != 0
- && languageCode != 25));
+ decodeString(
+ partType,
+ partNumberData,
+ languageCode != 0
+ && languageCode != 25));
break;
case 4:
setFruFileId(partNumberData);
@@ -182,12 +178,11 @@ private ArrayList readCustomInfo(
}
customInfo
.add(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- languageCode != 0
- && languageCode != 25));
+ decodeString(
+ partType,
+ partNumberData,
+ languageCode != 0
+ && languageCode != 25));
break;
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ChassisInfo.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ChassisInfo.java
index b412b81..97017c3 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ChassisInfo.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ChassisInfo.java
@@ -73,7 +73,7 @@ public ChassisInfo(final byte[] fruData, final int offset) {
int partType = (partNumber & 0xc0) >> 6;
- int partDataLength = (partNumber & 0x3f);
+ int partDataLength = partNumber & 0x3f;
if (partDataLength > 0 && partDataLength + currentOffset < fruData.length) {
@@ -92,19 +92,17 @@ public ChassisInfo(final byte[] fruData, final int offset) {
switch (index) {
case 0:
setChassisPartNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- true));
+ decodeString(
+ partType,
+ partNumberData,
+ true));
break;
case 1:
setChassisSerialNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- true));
+ decodeString(
+ partType,
+ partNumberData,
+ true));
break;
default:
if (partDataLength == 0) {
@@ -112,11 +110,10 @@ public ChassisInfo(final byte[] fruData, final int offset) {
}
customInfo
.add(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- true));
+ decodeString(
+ partType,
+ partNumberData,
+ true));
break;
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ProductInfo.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ProductInfo.java
index 105abb9..e0148fe 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ProductInfo.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/fru/record/ProductInfo.java
@@ -92,7 +92,7 @@ private ArrayList readCustomInfo(
int partType = (currentPartNumber & 0xc0) >> 6;
- int partDataLength = (currentPartNumber & 0x3f);
+ int partDataLength = currentPartNumber & 0x3f;
if (partDataLengthWithinBounds(fruData, currentOffset, partDataLength)) {
@@ -111,51 +111,45 @@ private ArrayList readCustomInfo(
switch (index) {
case 0:
setManufacturerName(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
case 1:
setProductName(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
case 2:
setProductModelNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
case 3:
setProductVersion(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
case 4:
setProductSerialNumber(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- true));
+ decodeString(
+ partType,
+ partNumberData,
+ true));
break;
case 5:
setAssetTag(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
case 6:
setFruFileId(partNumberData);
@@ -168,11 +162,10 @@ private ArrayList readCustomInfo(
}
customInfo
.add(
- FruRecord
- .decodeString(
- partType,
- partNumberData,
- isEnglishLanguageCode(languageCode)));
+ decodeString(
+ partType,
+ partNumberData,
+ isEnglishLanguageCode(languageCode)));
break;
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/GetSensorReading.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/GetSensorReading.java
index 8ab710b..991ff22 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/GetSensorReading.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/GetSensorReading.java
@@ -126,8 +126,7 @@ public ResponseData getResponseData(IpmiMessage message)
.setSensorState(
SensorState
.parseInt(
- (TypeConverter
- .byteToInt(raw[2])) & 0x3f));
+ TypeConverter.byteToInt(raw[2]) & 0x3f));
boolean[] states = null;
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/record/FullSensorRecord.java b/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/record/FullSensorRecord.java
index 8a7cc9f..db438a7 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/record/FullSensorRecord.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/commands/sdr/record/FullSensorRecord.java
@@ -229,7 +229,7 @@ protected void populateTypeSpecficValues(
int bExp = TypeConverter
.decode2sComplement(
- (TypeConverter.byteToInt(recordData[29]) & 0xf),
+ TypeConverter.byteToInt(recordData[29]) & 0xf,
3);
setB(getB() * Math.pow(10, bExp));
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/payload/sol/SolAckState.java b/src/main/java/org/metricshub/ipmi/core/coding/payload/sol/SolAckState.java
index c2571df..3cc0c94 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/payload/sol/SolAckState.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/payload/sol/SolAckState.java
@@ -49,7 +49,7 @@ public enum SolAckState {
* @return {@link SolAckState} extracted from byte
*/
public static SolAckState extractFromByte(byte value) {
- return TypeConverter.isBitSetOnPosition(ACK_BIT_NUMBER, value) ? SolAckState.NACK : SolAckState.ACK;
+ return TypeConverter.isBitSetOnPosition(ACK_BIT_NUMBER, value) ? NACK : ACK;
}
/**
@@ -62,7 +62,7 @@ public static SolAckState extractFromByte(byte value) {
public byte encodeInByte(final byte value) {
byte updatedValue = value;
- if (this == SolAckState.NACK) {
+ if (this == NACK) {
updatedValue = TypeConverter.setBitOnPosition(ACK_BIT_NUMBER, value);
}
diff --git a/src/main/java/org/metricshub/ipmi/core/coding/security/CipherSuite.java b/src/main/java/org/metricshub/ipmi/core/coding/security/CipherSuite.java
index a568357..a0556b1 100644
--- a/src/main/java/org/metricshub/ipmi/core/coding/security/CipherSuite.java
+++ b/src/main/java/org/metricshub/ipmi/core/coding/security/CipherSuite.java
@@ -59,9 +59,9 @@ public byte getId() {
public CipherSuite(byte id, byte authenticationAlgorithm,
byte confidentialityAlgorithm, byte integrityAlgorithm) {
this.id = id;
- this.authenticationAlgorithm = (authenticationAlgorithm);
- this.confidentialityAlgorithm = (confidentialityAlgorithm);
- this.integrityAlgorithm = (integrityAlgorithm);
+ this.authenticationAlgorithm = authenticationAlgorithm;
+ this.confidentialityAlgorithm = confidentialityAlgorithm;
+ this.integrityAlgorithm = integrityAlgorithm;
}
/**
diff --git a/src/main/java/org/metricshub/ipmi/core/common/TypeConverter.java b/src/main/java/org/metricshub/ipmi/core/common/TypeConverter.java
index 9a0d722..1499ceb 100644
--- a/src/main/java/org/metricshub/ipmi/core/common/TypeConverter.java
+++ b/src/main/java/org/metricshub/ipmi/core/common/TypeConverter.java
@@ -52,7 +52,7 @@ public static byte[] intToByteArray(int value) {
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
int offset = (b.length - 1 - i) * 8;
- b[i] = intToByte(((value >>> offset) & 0xFF));
+ b[i] = intToByte((value >>> offset) & 0xFF);
}
return b;
}
@@ -92,7 +92,7 @@ public static byte[] intToLittleEndianByteArray(int value) {
byte[] b = new byte[4];
for (int i = 3; i >= 0; i--) {
int offset = i * 8;
- b[i] = intToByte(((value >>> offset) & 0xFF));
+ b[i] = intToByte((value >>> offset) & 0xFF);
}
return b;
}
@@ -207,7 +207,7 @@ public static int wordToInt(byte[] word) {
byte[] tmpBytArray = new byte[4];
System.arraycopy(word, 0, tmpBytArray, 2, 2);
- return TypeConverter.byteArrayToInt(tmpBytArray);
+ return byteArrayToInt(tmpBytArray);
}
/**
@@ -225,7 +225,7 @@ public static int littleEndianWordToInt(byte[] word) {
byte[] tmpBytArray = new byte[4];
System.arraycopy(word, 0, tmpBytArray, 0, 2);
- return TypeConverter.littleEndianByteArrayToInt(tmpBytArray);
+ return littleEndianByteArrayToInt(tmpBytArray);
}
/**
@@ -292,7 +292,8 @@ public static int decode1sComplement(int value, int msb) {
int mask = 0x1 << i;
result |= mask;
}
- result = -(~result);
+ // the 1's complement magnitude is ~result, so the value is -(~result), i.e. result + 1
+ result = result + 1;
}
return result;
}
@@ -305,18 +306,16 @@ public static String decodeBcdPlus(byte[] text) {
for (int i = 0; i < text.length; ++i) {
result[2 * i] = decodeBcdPlusChar(
- TypeConverter
- .intToByte((TypeConverter.byteToInt(text[i]) & 0xf0) >> 4));
+ intToByte((byteToInt(text[i]) & 0xf0) >> 4));
result[2 * i + 1] = decodeBcdPlusChar(
- TypeConverter
- .intToByte(TypeConverter.byteToInt(text[i]) & 0xf));
+ intToByte(byteToInt(text[i]) & 0xf));
}
return new String(result);
}
private static char decodeBcdPlusChar(byte ch) {
- switch (TypeConverter.byteToInt(ch)) {
+ switch (byteToInt(ch)) {
case 0x0:
return '0';
case 0x1:
@@ -366,40 +365,28 @@ public static String decode6bitAscii(byte[] text) {
for (int i = 0; i < text.length; ++i) {
switch (i % 3) {
case 0:
- newText[index++] = TypeConverter
- .intToByte(
- TypeConverter
- .byteToInt(text[i])
- & 0x3f);
- newText[index] = TypeConverter
- .intToByte(
- (TypeConverter
- .byteToInt(text[i])
- & 0xc0) >> 6);
+ newText[index++] = intToByte(
+ byteToInt(text[i])
+ & 0x3f);
+ newText[index] = intToByte(
+ (byteToInt(text[i])
+ & 0xc0) >> 6);
break;
case 1:
- newText[index++] |= TypeConverter
- .intToByte(
- (TypeConverter
- .byteToInt(text[i])
- & 0xf) << 2);
- newText[index] = TypeConverter
- .intToByte(
- (TypeConverter
- .byteToInt(text[i])
- & 0xf0) >> 4);
+ newText[index++] |= intToByte(
+ (byteToInt(text[i])
+ & 0xf) << 2);
+ newText[index] = intToByte(
+ (byteToInt(text[i])
+ & 0xf0) >> 4);
break;
case 2:
- newText[index++] |= TypeConverter
- .intToByte(
- (TypeConverter
- .byteToInt(text[i])
- & 0x3) << 4);
- newText[index++] = TypeConverter
- .intToByte(
- (TypeConverter
- .byteToInt(text[i])
- & 0xfc) >> 2);
+ newText[index++] |= intToByte(
+ (byteToInt(text[i])
+ & 0x3) << 4);
+ newText[index++] = intToByte(
+ (byteToInt(text[i])
+ & 0xfc) >> 2);
break;
default:
break;
@@ -407,10 +394,8 @@ public static String decode6bitAscii(byte[] text) {
}
for (int i = 0; i < newText.length; ++i) {
- newText[i] = TypeConverter
- .intToByte(
- TypeConverter
- .byteToInt(newText[i]) + 0x20);
+ newText[i] = intToByte(
+ byteToInt(newText[i]) + 0x20);
}
return new String(newText, Charset.forName("US-ASCII"));
@@ -435,7 +420,7 @@ public static Date decodeDate(int date) {
* @return
*/
public static boolean isBitSetOnPosition(int position, byte value) {
- return ((value & SINGLE_BIT_MASKS[position]) > 0);
+ return (value & SINGLE_BIT_MASKS[position]) > 0;
}
public static byte setBitOnPosition(int position, byte value) {
diff --git a/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java b/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java
index 946bb9c..63ce1e6 100644
--- a/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java
+++ b/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java
@@ -130,6 +130,9 @@ public void close() {
public static int generateSessionlessTag() {
synchronized (SESSIONLESS_TAG) {
boolean wait = true;
+ // wait(1) clears the interrupt flag when it throws; restore it only once a tag is found,
+ // otherwise every following wait(1) would throw immediately and the loop would hot-spin
+ boolean interrupted = false;
while (wait) {
SESSIONLESS_TAG.incrementAndGet();
SESSIONLESS_TAG.set(SESSIONLESS_TAG.get() % 60);
@@ -142,13 +145,16 @@ public static int generateSessionlessTag() {
try {
SESSIONLESS_TAG.wait(1);
} catch (InterruptedException e) {
- // TODO log
+ interrupted = true;
}
}
}
synchronized (reservedTags) {
reservedTags.add(SESSIONLESS_TAG.get());
}
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
return SESSIONLESS_TAG.get();
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/connection/queue/MessageQueue.java b/src/main/java/org/metricshub/ipmi/core/connection/queue/MessageQueue.java
index 73eb7c7..45566b3 100644
--- a/src/main/java/org/metricshub/ipmi/core/connection/queue/MessageQueue.java
+++ b/src/main/java/org/metricshub/ipmi/core/connection/queue/MessageQueue.java
@@ -150,7 +150,7 @@ public int add(PayloadCoder request) {
try {
lastSequenceNumberLock.wait(1);
} catch (InterruptedException e) {
- // TODO log
+ Thread.currentThread().interrupt();
}
}
diff --git a/src/main/java/org/metricshub/ipmi/core/transport/UdpMessenger.java b/src/main/java/org/metricshub/ipmi/core/transport/UdpMessenger.java
index 4af8d19..4c08990 100644
--- a/src/main/java/org/metricshub/ipmi/core/transport/UdpMessenger.java
+++ b/src/main/java/org/metricshub/ipmi/core/transport/UdpMessenger.java
@@ -47,8 +47,6 @@ public class UdpMessenger extends Thread implements Messenger {
private boolean closing = false;
- private static final String DEFAULT_ADDRESS = "0.0.0.0";
-
/**
* Size of the message data buffer. Default
* {@link UdpMessenger#DEFAULTBUFFERSIZE}.
@@ -75,7 +73,7 @@ public int getPort() {
* @throws UnknownHostException
*/
public UdpMessenger(int port) throws SocketException, UnknownHostException {
- this(port, InetAddress.getByName(DEFAULT_ADDRESS));
+ this(port, null); // null binds the wildcard address
}
/**
@@ -116,8 +114,6 @@ public int getBufferSize() {
@Override
public void run() {
- super.run();
-
boolean run = true;
while (run) {
@@ -225,9 +221,9 @@ public synchronized void send(UdpMessage message) throws IOException {
message.getPort());
socket.send(packet);
try {
- Thread.sleep(1);
+ sleep(1);
} catch (InterruptedException e) {
- // TODO: log
+ currentThread().interrupt();
}
++sentPackets;
}
diff --git a/src/main/java/org/metricshub/ipmi/core/transport/UdpNotifier.java b/src/main/java/org/metricshub/ipmi/core/transport/UdpNotifier.java
index 731a582..99741ee 100644
--- a/src/main/java/org/metricshub/ipmi/core/transport/UdpNotifier.java
+++ b/src/main/java/org/metricshub/ipmi/core/transport/UdpNotifier.java
@@ -42,7 +42,5 @@ public void run() {
listener.notifyMessage(message);
}
}
-
- super.run();
}
}
diff --git a/src/test/java/org/metricshub/ipmi/core/common/TypeConverterTest.java b/src/test/java/org/metricshub/ipmi/core/common/TypeConverterTest.java
new file mode 100644
index 0000000..2e5394e
--- /dev/null
+++ b/src/test/java/org/metricshub/ipmi/core/common/TypeConverterTest.java
@@ -0,0 +1,25 @@
+package org.metricshub.ipmi.core.common;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class TypeConverterTest {
+
+ @Test
+ void decode1sComplement() {
+ // 4-bit 1's complement: 0111 = 7, 1000 = -7, 1110 = -1, 1111 = -0
+ assertEquals(7, TypeConverter.decode1sComplement(0x7, 3));
+ assertEquals(-7, TypeConverter.decode1sComplement(0x8, 3));
+ assertEquals(-1, TypeConverter.decode1sComplement(0xe, 3));
+ assertEquals(0, TypeConverter.decode1sComplement(0xf, 3));
+ assertEquals(0, TypeConverter.decode1sComplement(0x0, 3));
+ }
+
+ @Test
+ void decode2sComplement() {
+ assertEquals(7, TypeConverter.decode2sComplement(0x7, 3));
+ assertEquals(-8, TypeConverter.decode2sComplement(0x8, 3));
+ assertEquals(-1, TypeConverter.decode2sComplement(0xf, 3));
+ }
+}
diff --git a/src/test/java/org/metricshub/ipmi/core/connection/ConnectionManagerTest.java b/src/test/java/org/metricshub/ipmi/core/connection/ConnectionManagerTest.java
new file mode 100644
index 0000000..62aee05
--- /dev/null
+++ b/src/test/java/org/metricshub/ipmi/core/connection/ConnectionManagerTest.java
@@ -0,0 +1,46 @@
+package org.metricshub.ipmi.core.connection;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.jupiter.api.Test;
+
+class ConnectionManagerTest {
+
+ private static final int TAG_COUNT = 60;
+
+ @Test
+ void generateSessionlessTagKeepsWaitingWhenInterruptedOnSaturatedPool() throws Exception {
+ int[] tags = new int[TAG_COUNT];
+ try {
+ for (int i = 0; i < TAG_COUNT; i++) {
+ tags[i] = ConnectionManager.generateSessionlessTag();
+ }
+
+ AtomicInteger got = new AtomicInteger(-1);
+ AtomicBoolean interruptedOnReturn = new AtomicBoolean();
+ Thread waiter = new Thread(() -> {
+ got.set(ConnectionManager.generateSessionlessTag());
+ interruptedOnReturn.set(Thread.currentThread().isInterrupted());
+ });
+ waiter.start();
+ waiter.interrupt();
+ Thread.sleep(100);
+ assertTrue(waiter.isAlive(), "the interrupted request must keep waiting for a free tag");
+
+ ConnectionManager.freeTag(tags[0]);
+ waiter.join(5000);
+ assertFalse(waiter.isAlive(), "the request must complete once a tag is freed");
+ assertEquals(tags[0], got.get());
+ assertTrue(interruptedOnReturn.get(), "the interrupt flag must be restored on return");
+ } finally {
+ for (int tag : tags) {
+ ConnectionManager.freeTag(tag);
+ }
+ }
+ }
+}