From 70a1fde36ee6afa33f402613393c97c3f7fba024 Mon Sep 17 00:00:00 2001 From: Bertrand Martin Date: Wed, 7 Oct 2026 19:20:10 +0200 Subject: [PATCH 1/2] Fix the 117 PMD violations and gate pmd:check at verify (#114) Substantive fixes: - Delete DecoderRunner, the unreferenced main() harness (27 violations, see #99) - TypeConverter.decode1sComplement: replace -(~result) by result + 1 with a comment; add TypeConverterTest for 1's and 2's complement decoding - GetFrusRunner: log FRU chunk read and decode failures instead of swallowing them, so a lost packet truncating a FRU is visible (see #102) - AbstractIpmiRunner.close(): log the closeSession failure at debug - ConnectionManager, MessageQueue, UdpMessenger: restore the interrupt flag instead of swallowing InterruptedException (cancellation rework stays in #79) - SerialOverLan.waitForData: sleep 1 ms per iteration instead of busy-waiting - ReadFruData: drop the dead else-if (false) branch, keep the SPD TODO (#107) - UdpMessenger/UdpNotifier: drop super.run() from run(); bind the wildcard address with null instead of the hard-coded "0.0.0.0" - IpmiAsyncConnector.closeSession: drop the useless return Mechanical fixes: unnecessary self-qualifications in TypeConverter, the FRU records and SolAckState; useless parentheses in GetChassisStatusResponseData, CipherSuite, TypeConverter, GetSensorReading and FullSensorRecord. Build: run pmd:check at verify with pmd.xml (cpd-check awaits #115) and pin the reporting plugin to the same 3.28.0 so the site report matches the gate. Co-Authored-By: Claude Fable 5.1 --- AGENTS.md | 2 +- pom.xml | 24 +- .../client/runner/AbstractIpmiRunner.java | 2 +- .../ipmi/client/runner/GetFrusRunner.java | 10 +- .../core/api/async/IpmiAsyncConnector.java | 1 - .../ipmi/core/api/sol/SerialOverLan.java | 7 +- .../ipmi/core/coding/DecoderRunner.java | 1321 ----------------- .../chassis/GetChassisStatusResponseData.java | 46 +- .../core/coding/commands/fru/ReadFruData.java | 3 +- .../coding/commands/fru/record/BoardInfo.java | 55 +- .../commands/fru/record/ChassisInfo.java | 29 +- .../commands/fru/record/ProductInfo.java | 65 +- .../coding/commands/sdr/GetSensorReading.java | 3 +- .../commands/sdr/record/FullSensorRecord.java | 2 +- .../core/coding/payload/sol/SolAckState.java | 4 +- .../core/coding/security/CipherSuite.java | 6 +- .../ipmi/core/common/TypeConverter.java | 75 +- .../core/connection/ConnectionManager.java | 2 +- .../core/connection/queue/MessageQueue.java | 2 +- .../ipmi/core/transport/UdpMessenger.java | 10 +- .../ipmi/core/transport/UdpNotifier.java | 2 - .../ipmi/core/common/TypeConverterTest.java | 25 + 22 files changed, 196 insertions(+), 1500 deletions(-) delete mode 100644 src/main/java/org/metricshub/ipmi/core/coding/DecoderRunner.java create mode 100644 src/test/java/org/metricshub/ipmi/core/common/TypeConverterTest.java 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..73994e4 100644 --- a/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java +++ b/src/main/java/org/metricshub/ipmi/core/connection/ConnectionManager.java @@ -142,7 +142,7 @@ public static int generateSessionlessTag() { try { SESSIONLESS_TAG.wait(1); } catch (InterruptedException e) { - // TODO log + Thread.currentThread().interrupt(); } } } 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)); + } +} From b08a819853d980340ca59e448b492e65f40fb709 Mon Sep 17 00:00:00 2001 From: Bertrand Martin Date: Wed, 7 Oct 2026 19:31:14 +0200 Subject: [PATCH 2/2] Restore the interrupt flag only once a sessionless tag is found (#114) wait(1) clears the interrupt flag when it throws, so restoring it inside the loop made every following wait(1) throw immediately: an interrupted request hot-spun while all 60 sessionless tags were reserved. Remember the interrupt and restore it when the method returns; add a saturated-pool test. Co-Authored-By: Claude Fable 5.1 --- .../core/connection/ConnectionManager.java | 8 +++- .../connection/ConnectionManagerTest.java | 46 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/metricshub/ipmi/core/connection/ConnectionManagerTest.java 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 73994e4..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) { - Thread.currentThread().interrupt(); + interrupted = true; } } } synchronized (reservedTags) { reservedTags.add(SESSIONLESS_TAG.get()); } + if (interrupted) { + Thread.currentThread().interrupt(); + } return SESSIONLESS_TAG.get(); } } 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); + } + } + } +}