From 80e759ccb4576444833746e465dfc3243c31f0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BA=86=E7=81=BF?= Date: Tue, 26 Jul 2022 10:36:55 +0800 Subject: [PATCH 1/7] Markdown head format --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 40bcac235..542bef62d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#jSCSI - A Java iSCSI Framework +# jSCSI - A Java iSCSI Framework jSCSI is a feature-complete iSCSI implementation in Java only. Platform-independent and fast, jSCSI represents a premium example how low-level protocols can be pushed to higher levels. @@ -41,22 +41,22 @@ For further documentation and as an example, please refer to the examples in the * bundles: bundles containing the projects * pom.xml: Simple pom (yes we use Maven) -##License +## License This work is released in the public domain under the BSD 3-clause license -##Further information +## Further information The project is currently under refactoring, the documentation is accessible under http://jscsi.org (pointing to http://disy.github.com/jscsi/) and a mailinglist has been set up: https://mailman.uni-konstanz.de/mailman/listinfo/jscsi -##Publications +## Publications * A TechReport describes the second iteration of the framework: [PDF](http://nbn-resolving.de/urn:nbn:de:bsz:352-opus-84511) * The framework was presented at the Jazoon '07 as work in progress: [PDF](http://nbn-resolving.de/urn:nbn:de:bsz:352-opus-84424) * jSCSI acted as backend for a block visualization presented at the InfoVis 2006: [PDF](http://nbn-resolving.de/urn:nbn:de:bsz:352-opus-69096) -##Concluded Thesis +## Concluded Thesis * Target 1.0 (english): TO FOLLOW * Initiator 2.0 (german only): [PDF](http://nbn-resolving.de/urn:nbn:de:bsz:352-opus-130096) @@ -65,7 +65,7 @@ https://mailman.uni-konstanz.de/mailman/listinfo/jscsi Any questions, just contact sebastian.graf AT uni-konstanz.de -##Involved People +## Involved People jSCSI is maintained by: From a09e192c59511d4159343d70f35da863cad59715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BA=86=E7=81=BF?= Date: Tue, 26 Jul 2022 10:38:48 +0800 Subject: [PATCH 2/7] Markdown head format for GitHub --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 542bef62d..0b3c17ea8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ jSCSI contains a server (target), a client (initiator) and common classes to wor [![Build Status](https://secure.travis-ci.org/sebastiangraf/jSCSI.png)](http://travis-ci.org/sebastiangraf/jSCSI) -##Using jSCSI +## Using jSCSI * Get the latest jar over Github or Maven @@ -34,7 +34,7 @@ The schema and an example config are accessible as download as well and included For further documentation and as an example, please refer to the examples in the initiator- and target-module. -##Content +## Content * README: this readme file * LICENSE: license file From 3e15257aed395a92d81734280835807d05429575 Mon Sep 17 00:00:00 2001 From: ActiveVolcano Date: Fri, 29 Jul 2022 11:17:24 +0800 Subject: [PATCH 3/7] Fix redundant one block capacity --- .../connection/stage/fullfeature/ReadCapacityStage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadCapacityStage.java b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadCapacityStage.java index f27dbf886..2d88e7bd9 100644 --- a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadCapacityStage.java +++ b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadCapacityStage.java @@ -75,10 +75,10 @@ else if (opCode == ScsiOperationCode.READ_CAPACITY_16) // send PDU with requested READ CAPACITY parameter data ReadCapacityParameterData parameterData; if (cdb instanceof ReadCapacity10Cdb) - parameterData = new ReadCapacity10ParameterData(session.getStorageModule().getSizeInBlocks(),// returnedLogicalBlockAddress + parameterData = new ReadCapacity10ParameterData(session.getStorageModule().getSizeInBlocks() - 1,// returnedLogicalBlockAddress session.getStorageModule().getBlockSize());// logicalBlockLengthInBytes else - parameterData = new ReadCapacity16ParameterData(session.getStorageModule().getSizeInBlocks(),// returnedLogicalBlockAddress + parameterData = new ReadCapacity16ParameterData(session.getStorageModule().getSizeInBlocks() - 1,// returnedLogicalBlockAddress session.getStorageModule().getBlockSize());// logicalBlockLengthInBytes sendResponse(bhs.getInitiatorTaskTag(),// initiatorTaskTag, From 617fd3ab8153ae7366bf76824a6bfd22c36a95ac Mon Sep 17 00:00:00 2001 From: ActiveVolcano Date: Fri, 29 Jul 2022 11:28:50 +0800 Subject: [PATCH 4/7] Add Unit Serial Number page into INQUIRY command to avoid error log when Linux initiator (initiator) login --- .../stage/fullfeature/InquiryStage.java | 9 ++- .../scsi/inquiry/SupportedVpdPages.java | 15 +++-- .../scsi/inquiry/UnitSerialNumberPage.java | 67 +++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/UnitSerialNumberPage.java diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/InquiryStage.java b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/InquiryStage.java index 5e219a9d2..068fe41c1 100644 --- a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/InquiryStage.java +++ b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/InquiryStage.java @@ -14,6 +14,7 @@ import org.jscsi.target.scsi.inquiry.PageCode.VitalProductDataPageName; import org.jscsi.target.scsi.inquiry.StandardInquiryData; import org.jscsi.target.scsi.inquiry.SupportedVpdPages; +import org.jscsi.target.scsi.inquiry.UnitSerialNumberPage; import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData; import org.jscsi.target.settings.SettingsException; import org.jscsi.target.util.Debug; @@ -23,7 +24,7 @@ /** * A stage for processing INQUIRY SCSI commands. - * + * * @author Andreas Ergenzinger */ public class InquiryStage extends TargetFullFeatureStage { @@ -61,6 +62,7 @@ public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedExcep if (illegalFieldPointers != null) { // an illegal request has been made LOGGER.error("illegal INQUIRY request"); + LOGGER.error("CDB bytes: \n" + Debug.byteBufferToString(parser.getCDB())); responsePdu = createFixedFormatErrorPdu(illegalFieldPointers, bhs.getInitiatorTaskTag(), parser.getExpectedDataTransferLength()); @@ -92,6 +94,9 @@ public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedExcep case DEVICE_IDENTIFICATION : responseData = session.getTargetServer().getDeviceIdentificationVpdPage(); break; + case UNIT_SERIAL_NUMBER : + responseData = UnitSerialNumberPage.getInstance(); + break; default : // The initiator must not request unsupported mode pages. throw new InternetSCSIException(); @@ -100,7 +105,7 @@ public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedExcep // send response sendResponse(bhs.getInitiatorTaskTag(), parser.getExpectedDataTransferLength(), responseData); - + } } diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/SupportedVpdPages.java b/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/SupportedVpdPages.java index 9ed07e0c2..4069b2dcf 100644 --- a/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/SupportedVpdPages.java +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/SupportedVpdPages.java @@ -11,7 +11,7 @@ * This Vital Product Data page contains a list of the VPD page codes supported by the logical unit. *

* This class uses the singleton pattern since the list of supported Vital Product Data page requests will never change. - * + * * @author Andreas Ergenzinger */ public final class SupportedVpdPages implements IResponseData { @@ -29,14 +29,15 @@ public final class SupportedVpdPages implements IResponseData { /* * determine which pages to support must be in ascending order see PAGECode.VitalProductDataPageName */ - public static final byte[] SUPPORTED_VPD_PAGES = new byte[] { (byte) 0x00,// SUPPORTED_VPD_PAGES, - // mandatory - (byte) 0x83,// DECIVE_IDENTIFICATION, mandatory + public static final byte[] SUPPORTED_VPD_PAGES = new byte[] { + (byte) 0x00,// SUPPORTED_VPD_PAGES, mandatory + (byte) 0x80,// UNIT_SERIAL_NUMBER + (byte) 0x83,// DECIVE_IDENTIFICATION, mandatory }; /** * Returns the singleton. - * + * * @return the singleton */ public static SupportedVpdPages getInstance () { @@ -48,6 +49,7 @@ private SupportedVpdPages () { // private due to singleton pattern } + @Override public void serialize (ByteBuffer byteBuffer, int index) { // *** byte 0 *** @@ -82,13 +84,14 @@ public void serialize (ByteBuffer byteBuffer, int index) { byteBuffer.put(SUPPORTED_VPD_PAGES[i]); } + @Override public int size () { return HEADER_SIZE + SUPPORTED_VPD_PAGES.length; } /** * Returns true for those and only for those VPD Page Codes which are supported by the jSCSI Target. - * + * * @param vitalProductDataPageName VPD Page Name whose support is inquired * @return true for those and only for those VPD Page Codes which are supported by the jSCSI Target */ diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/UnitSerialNumberPage.java b/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/UnitSerialNumberPage.java new file mode 100644 index 000000000..5f7da397b --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/inquiry/UnitSerialNumberPage.java @@ -0,0 +1,67 @@ +package org.jscsi.target.scsi.inquiry; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.scsi.IResponseData; + + +/** + * The Unit Serial Number page provides a product serial number for the target or logical unit. + *

+ * This class uses the singleton pattern since the content of the Unit Serial Number page will never change. + * + * @author CHEN Qingcan + */ +public class UnitSerialNumberPage implements IResponseData { + + /** + * The singleton. + */ + private static UnitSerialNumberPage instance; + + /** + * Returns the singleton. + * + * @return the singleton + */ + public static synchronized UnitSerialNumberPage getInstance () { + if (instance == null) instance = new UnitSerialNumberPage (); + return instance; + } + + private UnitSerialNumberPage () { + // private due to singleton pattern + } + + private static final byte PAGE_CODE = (byte) 0x80; + private static final byte PAGE_LENGTH = (byte) 0x08; + + @Override + public void serialize (ByteBuffer out, int index) { + out.position (index); + // PERIPHERAL QUALIFIER and PERIPHERAL DEVICE TYPE + // See DeviceIdentificationVpdPage.peripheralQualifierAndPeripheralDeviceType for details. + out.put ((byte) 0); + // PAGE CODE (80h) + out.put (PAGE_CODE); + // Reserved + out.put ((byte) 0); + // PAGE LENGTH + // The PAGE LENGTH field specifies the length in bytes of the product serial number page. + // Older products that only support the Product Serial Number parameter will have a page length of 08h, + // while newer products that support both parameters will have a page length of 14h. + out.put (PAGE_LENGTH); + // Product Serial Number + // The Product Serial Number field contains ASCII data that is vendor-assigned serial number. + // The least significant ASCII character of the serial number shall appear as the last byte in the Data-In Buffer. + // If the product serial number is not available, the target shall return ASCII spaces (20h) in this field. + for (int i = 0 ; i < PAGE_LENGTH ; i++) out.put ((byte) 0x20); + } + + @Override + public int size () { + return 4 + PAGE_LENGTH; + } + +} From ff76938e4deb3e3511c7131edc97105de4a973f4 Mon Sep 17 00:00:00 2001 From: ActiveVolcano Date: Fri, 29 Jul 2022 11:35:20 +0800 Subject: [PATCH 5/7] Support PB level storage by adding READ (16), READ (12), WRITE (16), WRITE (12), REPORT SUPPORTED OPERATION CODES commands --- .../org/jscsi/parser/ProtocolDataUnit.java | 63 +++++++++++-------- .../phase/TargetFullFeaturePhase.java | 30 ++++++--- .../stage/fullfeature/ReadStage.java | 14 ++++- .../stage/fullfeature/ReportOpCodesStage.java | 57 +++++++++++++++++ .../stage/fullfeature/WriteStage.java | 20 +++--- .../org/jscsi/target/scsi/cdb/OpCodesCDB.java | 35 +++++++++++ .../org/jscsi/target/scsi/cdb/Read12Cdb.java | 46 ++++++++++++++ .../org/jscsi/target/scsi/cdb/Read16Cdb.java | 46 ++++++++++++++ .../target/scsi/cdb/ScsiOperationCode.java | 33 +++++++--- .../org/jscsi/target/scsi/cdb/Write12Cdb.java | 46 ++++++++++++++ .../org/jscsi/target/scsi/cdb/Write16Cdb.java | 46 ++++++++++++++ .../jscsi/target/scsi/report/OneOpCode.java | 40 ++++++++++++ .../java/org/jscsi/target/util/ReadWrite.java | 53 ++++++++++------ 13 files changed, 457 insertions(+), 72 deletions(-) create mode 100644 bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReportOpCodesStage.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/cdb/OpCodesCDB.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read12Cdb.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read16Cdb.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write12Cdb.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write16Cdb.java create mode 100644 bundles/target/src/main/java/org/jscsi/target/scsi/report/OneOpCode.java diff --git a/bundles/commons/src/main/java/org/jscsi/parser/ProtocolDataUnit.java b/bundles/commons/src/main/java/org/jscsi/parser/ProtocolDataUnit.java index 7f16ea6d6..935404735 100644 --- a/bundles/commons/src/main/java/org/jscsi/parser/ProtocolDataUnit.java +++ b/bundles/commons/src/main/java/org/jscsi/parser/ProtocolDataUnit.java @@ -1,13 +1,13 @@ /** * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Iterator; +import com.google.common.io.BaseEncoding; import org.jscsi.exception.InternetSCSIException; import org.jscsi.parser.datasegment.AbstractDataSegment; import org.jscsi.parser.datasegment.IDataSegmentIterator.IDataSegmentChunk; @@ -39,7 +40,7 @@ *

ProtocolDataUnit

*

* This class encapsulates a Protocol Data Unit (PDU), which is defined in the iSCSI Standard (RFC 3720). - * + * * @author Volker Wildi */ public final class ProtocolDataUnit { @@ -95,7 +96,7 @@ public final class ProtocolDataUnit { /** * Default constructor, creates a new, empty ProtcolDataUnit object. - * + * * @param initHeaderDigest The instance of the digest to use for the Basic Header Segment protection. * @param initDataDigest The instance of the digest to use for the Data Segment protection. */ @@ -115,7 +116,7 @@ public ProtocolDataUnit (final IDigest initHeaderDigest, final IDigest initDataD /** * Serialize all informations of this PDU object to its byte representation. - * + * * @return The byte representation of this PDU. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. * @throws IOException if an I/O error occurs. @@ -134,7 +135,7 @@ public final ByteBuffer serialize () throws InternetSCSIException , IOException } offset += serializeAdditionalHeaderSegments(pdu, offset); - + // write header digest // TODO: Move CRC calculation in BasicHeaderSegment.serialize? if (basicHeaderSegment.getParser().canHaveDigests()) { @@ -150,12 +151,12 @@ public final ByteBuffer serialize () throws InternetSCSIException , IOException offset += serializeDigest(pdu, dataDigest); } - return (ByteBuffer) pdu.rewind(); + return pdu.rewind(); } /** * Deserializes (parses) a given byte representation of a PDU to an PDU object. - * + * * @param pdu The byte representation of an PDU to parse. * @return The number of bytes, which are serialized. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. @@ -178,7 +179,7 @@ public final int deserialize (final ByteBuffer pdu) throws InternetSCSIException /** * Deserializes a given array starting from offset 0 and store the informations in the * BasicHeaderSegment object.. - * + * * @param bhs The array to read from. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. * @throws DigestException There is a mismatch of the digest. @@ -202,7 +203,7 @@ private final int deserializeBasicHeaderSegment (final ByteBuffer bhs) throws In /** * Deserializes a array (starting from offset 0) and store the informations to the * AdditionalHeaderSegment object. - * + * * @param pdu The array to read from. * @return The length of the read bytes. * @throws InternetSCSIException If any violation of the iSCSI-Standard emerge. @@ -215,7 +216,7 @@ private final int deserializeAdditionalHeaderSegments (final ByteBuffer pdu) thr /** * Deserializes a array (starting from the given offset) and store the informations to the * AdditionalHeaderSegment object. - * + * * @param pdu The ByteBuffer to read from. * @param offset The offset to start from. * @return The length of the written bytes. @@ -241,7 +242,7 @@ private final int deserializeAdditionalHeaderSegments (final ByteBuffer pdu, fin /** * Serialize all the contained additional header segments to the destination array starting from the given offset. - * + * * @param dst The destination array to write in. * @param offset The offset to start to write in dst. * @return The written length. @@ -259,7 +260,7 @@ private final int serializeAdditionalHeaderSegments (final ByteBuffer dst, final /** * Serializes the data segment (binary or key-value pairs) to a destination array, staring from offset to write. - * + * * @param dst The array to write in. * @param offset The start offset to start from in dst. * @return The written length. @@ -276,7 +277,7 @@ public final int serializeDataSegment (final ByteBuffer dst, final int offset) t /** * Deserializes a array (starting from the given offset) and store the informations to the Data Segment. - * + * * @param pdu The array to read from. * @param offset The offset to start from. * @return The length of the written bytes. @@ -312,7 +313,7 @@ private final int deserializeDataSegment (final ByteBuffer pdu, final int offset /** * Writes this ProtocolDataUnit object to the given SocketChannel. - * + * * @param sChannel SocketChannel to write to. * @return The number of bytes written, possibly zero. * @throws InternetSCSIException if any violation of the iSCSI-Standard emerge. @@ -337,7 +338,7 @@ public final int write (final SocketChannel sChannel) throws InternetSCSIExcepti /** * Reads from the given SocketChannel all the neccassary bytes to fill this PDU. - * + * * @param sChannel SocketChannel to read from. * @return The number of bytes, possibly zero,or -1 if the channel has reached end-of-stream * @throws IOException if an I/O error occurs. @@ -420,7 +421,7 @@ public final void clear () { /** * Returns an iterator to all contained Additional Header Segment in this PDU. - * + * * @return The iterator to the contained Additional Header Segment. * @see AdditionalHeaderSegment */ @@ -431,7 +432,7 @@ public final Iterator getAdditionalHeaderSegments () { /** * Returns the Basic Header Segment contained in this PDU. - * + * * @return The Basic Header Segment. * @see BasicHeaderSegment */ @@ -442,7 +443,7 @@ public final BasicHeaderSegment getBasicHeaderSegment () { /** * Gets the data segment in this PDU. - * + * * @return The data segment of this ProtocolDataUnit object. */ public final ByteBuffer getDataSegment () { @@ -458,7 +459,7 @@ public final void setDataSegment (final ByteBuffer dataSegment) { /** * Sets a new data segment in this PDU. - * + * * @param chunk The new data segment of this ProtocolDataUnit object. */ public final void setDataSegment (final IDataSegmentChunk chunk) { @@ -472,7 +473,7 @@ public final void setDataSegment (final IDataSegmentChunk chunk) { /** * Returns the instance of the used digest algorithm for the header. - * + * * @return The instance of the header digest. */ public final IDigest getHeaderDigest () { @@ -482,7 +483,7 @@ public final IDigest getHeaderDigest () { /** * Sets the digest of the header to use for data integrity. - * + * * @param newHeaderDigest An instance of the new header digest. */ public final void setHeaderDigest (final IDigest newHeaderDigest) { @@ -492,7 +493,7 @@ public final void setHeaderDigest (final IDigest newHeaderDigest) { /** * Returns the instance of the used digest algorithm for the data segment. - * + * * @return The instance of the data digest. */ public final IDigest getDataDigest () { @@ -502,7 +503,7 @@ public final IDigest getDataDigest () { /** * Sets the digest of the data segment to use for data integrity. - * + * * @param newDataDigest An instance of the new data segment digest. */ public final void setDataDigest (final IDigest newDataDigest) { @@ -516,15 +517,23 @@ public final void setDataDigest (final IDigest newDataDigest) { /** {@inheritDoc} */ @Override public final String toString () { - final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE); sb.append(basicHeaderSegment.toString()); - for (AdditionalHeaderSegment ahs : additionalHeaderSegments) { sb.append(ahs.toString()); } + if (dataSegment.limit () > 0) { + sb.append (" DataSegment (first 16 bytes): 0x"); + byte[] preview = new byte [Math.min (dataSegment.limit (), 16)]; + // NOT to use mark and reset because + // "If the mark is defined and larger than the new position then it is discarded." + int pos = dataSegment.position (); + dataSegment.position (0).get (preview).position (pos); + sb.append (BaseEncoding.base16 ().withSeparator (" ", 2).encode (preview)); + } + return sb.toString(); } @@ -567,7 +576,7 @@ public int hashCode() { /** * Calculates the needed size (in bytes) of serializing this object. - * + * * @return The needed size to store this object. */ private final int calcSize () { diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/phase/TargetFullFeaturePhase.java b/bundles/target/src/main/java/org/jscsi/target/connection/phase/TargetFullFeaturePhase.java index cd948da22..a52b3976a 100644 --- a/bundles/target/src/main/java/org/jscsi/target/connection/phase/TargetFullFeaturePhase.java +++ b/bundles/target/src/main/java/org/jscsi/target/connection/phase/TargetFullFeaturePhase.java @@ -20,6 +20,7 @@ import org.jscsi.target.connection.stage.fullfeature.ReadCapacityStage; import org.jscsi.target.connection.stage.fullfeature.ReadStage; import org.jscsi.target.connection.stage.fullfeature.ReportLunsStage; +import org.jscsi.target.connection.stage.fullfeature.ReportOpCodesStage; import org.jscsi.target.connection.stage.fullfeature.RequestSenseStage; import org.jscsi.target.connection.stage.fullfeature.SendDiagnosticStage; import org.jscsi.target.connection.stage.fullfeature.TargetFullFeatureStage; @@ -35,7 +36,7 @@ /** * Objects of this class represent the Target Full Feature Phase of a connection. - * + * * @see TargetPhase * @author Andreas Ergenzinger */ @@ -56,7 +57,7 @@ public final class TargetFullFeaturePhase extends TargetPhase { /** * The constructor. - * + * * @param connection {@inheritDoc} */ public TargetFullFeaturePhase (Connection connection) { @@ -66,7 +67,7 @@ public TargetFullFeaturePhase (Connection connection) { /** * Starts the full feature phase. - * + * * @return {@inheritDoc} * @throws OperationNotSupportedException {@inheritDoc} * @throws IOException {@inheritDoc} @@ -75,6 +76,7 @@ public TargetFullFeaturePhase (Connection connection) { * @throws DigestException {@inheritDoc} * @throws SettingsException {@inheritDoc} */ + @Override public boolean execute () throws DigestException , IOException , InterruptedException , InternetSCSIException , SettingsException { running = true; @@ -89,6 +91,7 @@ public boolean execute () throws DigestException , IOException , InterruptedExce if (connection.getTargetSession().isNormalSession()) { final SCSICommandParser parser = (SCSICommandParser) bhs.getParser(); ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0)); + int scsiServiceAction = parser.getCDB().get(1) & 0x1F; LOGGER.debug("scsiOpCode = " + scsiOpCode);// log SCSI // Operation Code @@ -121,21 +124,32 @@ public boolean execute () throws DigestException , IOException , InterruptedExce case SEND_DIAGNOSTIC : stage = new SendDiagnosticStage(this); break; - case READ_CAPACITY_10 :// use common read capacity stage - case READ_CAPACITY_16 : + case READ_CAPACITY_16 :// use common read capacity stage + case READ_CAPACITY_10 : stage = new ReadCapacityStage(this); break; - case WRITE_6 :// use common write stage + case WRITE_16 :// use common write stage + case WRITE_12 : case WRITE_10 : + case WRITE_6 : stage = new WriteStage(this); break; - case READ_6 :// use common read stage + case READ_16 :// use common read stage + case READ_12 : case READ_10 : + case READ_6 : stage = new ReadStage(this); break; case REPORT_LUNS : stage = new ReportLunsStage(this); break; + case REPORT_OP_CODES : + if (scsiServiceAction == 0x0C) { + stage = new ReportOpCodesStage(this); + } else { + scsiOpCode = null; + } + break; default : scsiOpCode = null; @@ -175,7 +189,7 @@ public boolean execute () throws DigestException , IOException , InterruptedExce return false; } - + /** * Stopping this phases execution */ diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadStage.java b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadStage.java index 739345575..21165a89c 100644 --- a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadStage.java +++ b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReadStage.java @@ -13,17 +13,20 @@ import org.jscsi.target.connection.phase.TargetFullFeaturePhase; import org.jscsi.target.scsi.ScsiResponseDataSegment; import org.jscsi.target.scsi.cdb.Read10Cdb; +import org.jscsi.target.scsi.cdb.Read12Cdb; +import org.jscsi.target.scsi.cdb.Read16Cdb; import org.jscsi.target.scsi.cdb.Read6Cdb; import org.jscsi.target.scsi.cdb.ReadCdb; import org.jscsi.target.scsi.cdb.ScsiOperationCode; import org.jscsi.target.settings.SettingsException; +import org.jscsi.target.util.Debug; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A stage for processing READ (6) and READ (10) SCSI commands. - * + * * @author Andreas Ergenzinger */ public class ReadStage extends ReadOrWriteStage { @@ -54,7 +57,11 @@ public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedExcep // get the Read(6) or Read(10) CDB ReadCdb cdb; final ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0)); - if (scsiOpCode == ScsiOperationCode.READ_10)// most likely option first + if (scsiOpCode == ScsiOperationCode.READ_16)// most likely option first + cdb = new Read16Cdb(parser.getCDB()); + else if (scsiOpCode == ScsiOperationCode.READ_12) + cdb = new Read12Cdb(parser.getCDB()); + else if (scsiOpCode == ScsiOperationCode.READ_10) cdb = new Read10Cdb(parser.getCDB()); else if (scsiOpCode == ScsiOperationCode.READ_6) cdb = new Read6Cdb(parser.getCDB()); @@ -71,7 +78,8 @@ else if (scsiOpCode == ScsiOperationCode.READ_6) if (cdb.getIllegalFieldPointers() != null) { // the command must fail - LOGGER.debug("illegal field in Read CDB"); + LOGGER.error("illegal field in Read CDB"); + LOGGER.error("CDB:\n" + Debug.byteBufferToString(parser.getCDB())); // create and send error PDU and leave stage final ProtocolDataUnit responsePdu = createFixedFormatErrorPdu(cdb.getIllegalFieldPointers(),// senseKeySpecificData diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReportOpCodesStage.java b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReportOpCodesStage.java new file mode 100644 index 000000000..c441f69f9 --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/ReportOpCodesStage.java @@ -0,0 +1,57 @@ +package org.jscsi.target.connection.stage.fullfeature; + + +import java.io.IOException; +import java.security.DigestException; + +import org.jscsi.exception.InternetSCSIException; +import org.jscsi.parser.BasicHeaderSegment; +import org.jscsi.parser.ProtocolDataUnit; +import org.jscsi.parser.scsi.SCSICommandParser; +import org.jscsi.target.connection.phase.TargetFullFeaturePhase; +import org.jscsi.target.scsi.cdb.OpCodesCDB; +import org.jscsi.target.scsi.report.OneOpCode; +import org.jscsi.target.settings.SettingsException; +import org.jscsi.target.util.Debug; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * A stage for processing REPORT SUPPORTED OPERATION CODES SCSI commands. + * + * @author CHEN Qingcan + */ +public class ReportOpCodesStage extends TargetFullFeatureStage { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReportOpCodesStage.class); + + public ReportOpCodesStage (TargetFullFeaturePhase targetFullFeaturePhase) { + super(targetFullFeaturePhase); + } + + @Override + public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedException , InternetSCSIException , DigestException , SettingsException { + final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); + final SCSICommandParser parser = (SCSICommandParser) bhs.getParser(); + + // get command details in CDB + if (LOGGER.isDebugEnabled()) {// print CDB bytes + LOGGER.debug("CDB bytes: \n" + Debug.byteBufferToString(parser.getCDB())); + } + final OpCodesCDB cdb = new OpCodesCDB(parser.getCDB()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("cdb.getAllocationLength() = " + cdb.getAllocationLength()); + LOGGER.debug("cdb.isNormalACA() = " + cdb.isNormalACA()); + LOGGER.debug("cdb.getReportingOptions() = " + cdb.getReportingOptions()); + } + + // send response + sendResponse ( + bhs.getInitiatorTaskTag(), + parser.getExpectedDataTransferLength(), + new OneOpCode (cdb.getReportingOptions()) + ); + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/WriteStage.java b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/WriteStage.java index e06857d88..96a2ffe18 100644 --- a/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/WriteStage.java +++ b/bundles/target/src/main/java/org/jscsi/target/connection/stage/fullfeature/WriteStage.java @@ -18,6 +18,8 @@ import org.jscsi.target.scsi.ScsiResponseDataSegment; import org.jscsi.target.scsi.cdb.ScsiOperationCode; import org.jscsi.target.scsi.cdb.Write10Cdb; +import org.jscsi.target.scsi.cdb.Write12Cdb; +import org.jscsi.target.scsi.cdb.Write16Cdb; import org.jscsi.target.scsi.cdb.Write6Cdb; import org.jscsi.target.scsi.cdb.WriteCdb; import org.jscsi.target.settings.SettingsException; @@ -27,8 +29,8 @@ /** - * A stage for processing WRITE (6) and WRITE (10) SCSI commands. - * + * A stage for processing WRITE (6), (10), (12), (16) SCSI commands. + * * @author Andreas Ergenzinger */ public final class WriteStage extends ReadOrWriteStage { @@ -47,7 +49,7 @@ public WriteStage (TargetFullFeaturePhase targetFullFeaturePhase) { /** * Is used for checking if the PDUs received in a Data-Out sequence actually are Data-Out PDU and if the PDUs have * been received in order. - * + * * @param parser the {@link AbstractMessageParser} subclass instance retrieved from the {@link ProtocolDataUnit}'s * {@link BasicHeaderSegment} * @throws InternetSCSIException if an unexpected PDU has been received @@ -90,7 +92,11 @@ public void execute (ProtocolDataUnit pdu) throws IOException , DigestException final int initiatorTaskTag = bhs.getInitiatorTaskTag(); WriteCdb cdb; final ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0)); - if (scsiOpCode == ScsiOperationCode.WRITE_10) + if (scsiOpCode == ScsiOperationCode.WRITE_16) + cdb = new Write16Cdb(parser.getCDB()); + else if (scsiOpCode == ScsiOperationCode.WRITE_12) + cdb = new Write12Cdb(parser.getCDB()); + else if (scsiOpCode == ScsiOperationCode.WRITE_10) cdb = new Write10Cdb(parser.getCDB()); else if (scsiOpCode == ScsiOperationCode.WRITE_6) cdb = new Write6Cdb(parser.getCDB()); @@ -117,9 +123,9 @@ else if (scsiOpCode == ScsiOperationCode.WRITE_6) * WriteStage is simply left early (without closing the connection), the initiator may send additional * unsolicited Data-Out PDUs, which the jSCSI Target is currently unable to ignore or process properly. */ - LOGGER.debug("illegal field in Write CDB"); - LOGGER.debug("CDB:\n" + Debug.byteBufferToString(parser.getCDB())); - + LOGGER.error("illegal field in Write CDB"); + LOGGER.error("CDB:\n" + Debug.byteBufferToString(parser.getCDB())); + // Not necessarily close the connection // create and send error PDU and leave stage diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/OpCodesCDB.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/OpCodesCDB.java new file mode 100644 index 000000000..36d1d3cec --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/OpCodesCDB.java @@ -0,0 +1,35 @@ +package org.jscsi.target.scsi.cdb; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.util.ReadWrite; + + +/** + * This class represents Command Descriptor Blocks for the REPORT SUPPORTED OPERATION CODES SCSI command. + * + * @author CHEN Qingcan + */ +public class OpCodesCDB extends CommandDescriptorBlock { + + private final int inReportingOptions; + private final int inAllocationLength; + + public OpCodesCDB (ByteBuffer buffer) { + super (buffer); + inReportingOptions = ReadWrite.readOneByteInt (buffer, 2) & 7; + inAllocationLength = ReadWrite.readFourByteInt (buffer, 6); + } + + /** REPORTING OPTIONS field */ + public int getReportingOptions () { + return inReportingOptions; + } + + /** ALLOCATION LENGTH field */ + public int getAllocationLength () { + return inAllocationLength; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read12Cdb.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read12Cdb.java new file mode 100644 index 000000000..8a714b913 --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read12Cdb.java @@ -0,0 +1,46 @@ +package org.jscsi.target.scsi.cdb; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.util.ReadWrite; + + +/** + * This class represents Command Descriptor Blocks for the READ (12) SCSI command. + * + *

+ * The READ (12) command requests that the device server read the specified logical block(s) and transfer them to + * the data-in buffer. Each logical block read includes user data and, if the medium is formatted with protection information + * enabled, protection information. Each logical block transferred includes user data and may include protection information, + * based on the RDPROTECT field and the medium format. + * + * @author CHEN Qingcan + */ +public final class Read12Cdb extends ReadCdb { + + public Read12Cdb (final ByteBuffer buffer) { + super(buffer);// OPERATION CODE + CONTROL + } + + @Override + protected long deserializeLogicalBlockAddress (ByteBuffer buffer) { + return ReadWrite.readUnsignedInt (buffer, 2); + } + + @Override + protected int deserializeTransferLength (ByteBuffer buffer) { + return ReadWrite.readFourByteInt (buffer, 6); + } + + @Override + protected int getLogicalBlockAddressFieldIndex () { + return 2; + } + + @Override + protected int getTransferLengthFieldIndex () { + return 6; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read16Cdb.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read16Cdb.java new file mode 100644 index 000000000..e789fa5bf --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Read16Cdb.java @@ -0,0 +1,46 @@ +package org.jscsi.target.scsi.cdb; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.util.ReadWrite; + + +/** + * This class represents Command Descriptor Blocks for the READ (16) SCSI command. + * + *

+ * The READ (16) command requests that the device server read the specified logical block(s) and transfer them to + * the data-in buffer. Each logical block read includes user data and, if the medium is formatted with protection information + * enabled, protection information. Each logical block transferred includes user data and may include protection information, + * based on the RDPROTECT field and the medium format. + * + * @author CHEN Qingcan + */ +public final class Read16Cdb extends ReadCdb { + + public Read16Cdb (final ByteBuffer buffer) { + super(buffer);// OPERATION CODE + CONTROL + } + + @Override + protected long deserializeLogicalBlockAddress (ByteBuffer buffer) { + return ReadWrite.readEightByteInt (buffer, 2); + } + + @Override + protected int deserializeTransferLength (ByteBuffer buffer) { + return ReadWrite.readFourByteInt (buffer, 10); + } + + @Override + protected int getLogicalBlockAddressFieldIndex () { + return 2; + } + + @Override + protected int getTransferLengthFieldIndex () { + return 10; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/ScsiOperationCode.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/ScsiOperationCode.java index 803981e3a..6cd7a83f0 100644 --- a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/ScsiOperationCode.java +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/ScsiOperationCode.java @@ -9,12 +9,31 @@ * thirty-two command codes in each group. A total of 256 possible operation codes exist. *

* The value of the GROUP CODE field specifies the {@link CommandDescriptorBlock}'s length. - * + * * @see CdbType * @author Andreas Ergenzinger */ public enum ScsiOperationCode { - TEST_UNIT_READY((byte) 0x00), REQUEST_SENSE((byte) 0x03), FORMAT_UNIT((byte) 0x04), READ_6((byte) 0x08), WRITE_6((byte) 0x0a), INQUIRY((byte) 0x12), MODE_SELECT_6((byte) 0x15), MODE_SENSE_6((byte) 0x1a), SEND_DIAGNOSTIC((byte) 0x1d), READ_CAPACITY_10((byte) 0x25), READ_10((byte) 0x28), WRITE_10((byte) 0x2a), READ_CAPACITY_16((byte) 0x9e), REPORT_LUNS((byte) 0xa0); + TEST_UNIT_READY ((byte) 0x00), + REQUEST_SENSE ((byte) 0x03), + FORMAT_UNIT ((byte) 0x04), + READ_6 ((byte) 0x08), + WRITE_6 ((byte) 0x0a), + INQUIRY ((byte) 0x12), + MODE_SELECT_6 ((byte) 0x15), + MODE_SENSE_6 ((byte) 0x1a), + SEND_DIAGNOSTIC ((byte) 0x1d), + READ_CAPACITY_10 ((byte) 0x25), + READ_10 ((byte) 0x28), + WRITE_10 ((byte) 0x2a), + READ_16 ((byte) 0x88), + WRITE_16 ((byte) 0x8a), + READ_CAPACITY_16 ((byte) 0x9e), + REPORT_LUNS ((byte) 0xa0), + /** REPORT SUPPORTED OPERATION CODES */ + REPORT_OP_CODES ((byte) 0xa3), + READ_12 ((byte) 0xa8), + WRITE_12 ((byte) 0xaa); /** * The serialized value of the operation code. @@ -36,7 +55,7 @@ public enum ScsiOperationCode { /** * Returns the {@link ScsiOperationCode} corresponding to the passed byte value. - * + * * @param value the serialized value of a SCSI operation code * @return the corresponding {@link ScsiOperationCode} or null if the passed value is not known by the * jSCSI Target @@ -51,7 +70,7 @@ private ScsiOperationCode (final byte value) { /** * Returns the serialized value of the operation code. - * + * * @return the serialized value of the operation code */ public final byte value () { @@ -60,7 +79,7 @@ public final byte value () { /** * The three-bit GROUP CODE field provides for eight groups of command codes. - * + * * @return the three-bit GROUP CODE field */ public int getGroupCode () { @@ -69,7 +88,7 @@ public int getGroupCode () { /** * Returns the five-bit COMMAND CODE field. - * + * * @return the five-bit COMMAND CODE field */ public int getCommandCode () { @@ -78,7 +97,7 @@ public int getCommandCode () { /** * Returns the {@link CdbType} for this operation code. - * + * * @return the {@link CdbType} for this operation code */ public CdbType getCdbType () { diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write12Cdb.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write12Cdb.java new file mode 100644 index 000000000..e22778f14 --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write12Cdb.java @@ -0,0 +1,46 @@ +package org.jscsi.target.scsi.cdb; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.util.ReadWrite; + + +/** + * This class represents Command Descriptor Blocks for the WRITE (12) SCSI command. + * + *

+ * The WRITE (12) command requests that the device server transfer the specified logical block(s) from the data-out + * buffer and write them. Each logical block transferred includes user data and may include protection information, based on the + * WRPROTECT field and the medium format. Each logical block written includes user data and, if the medium is formatted with + * protection information enabled, protection information. + * + * @author CHEN Qingcan + */ +public class Write12Cdb extends WriteCdb { + + public Write12Cdb (ByteBuffer buffer) { + super(buffer);// OPERATION CODE + CONTROL + } + + @Override + protected long deserializeLogicalBlockAddress (ByteBuffer buffer) { + return ReadWrite.readUnsignedInt (buffer, 2); + } + + @Override + protected int deserializeTransferLength (ByteBuffer buffer) { + return ReadWrite.readFourByteInt (buffer, 6); + } + + @Override + protected int getLogicalBlockAddressFieldIndex () { + return 2; + } + + @Override + protected int getTransferLengthFieldIndex () { + return 6; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write16Cdb.java b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write16Cdb.java new file mode 100644 index 000000000..34924bfad --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/cdb/Write16Cdb.java @@ -0,0 +1,46 @@ +package org.jscsi.target.scsi.cdb; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.util.ReadWrite; + + +/** + * This class represents Command Descriptor Blocks for the WRITE (16) SCSI command. + * + *

+ * The WRITE (16) command requests that the device server transfer the specified logical block(s) from the data-out + * buffer and write them. Each logical block transferred includes user data and may include protection information, based on the + * WRPROTECT field and the medium format. Each logical block written includes user data and, if the medium is formatted with + * protection information enabled, protection information. + * + * @author CHEN Qingcan + */ +public class Write16Cdb extends WriteCdb { + + public Write16Cdb (ByteBuffer buffer) { + super(buffer);// OPERATION CODE + CONTROL + } + + @Override + protected long deserializeLogicalBlockAddress (ByteBuffer buffer) { + return ReadWrite.readEightByteInt (buffer, 2); + } + + @Override + protected int deserializeTransferLength (ByteBuffer buffer) { + return ReadWrite.readFourByteInt (buffer, 10); + } + + @Override + protected int getLogicalBlockAddressFieldIndex () { + return 2; + } + + @Override + protected int getTransferLengthFieldIndex () { + return 10; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/scsi/report/OneOpCode.java b/bundles/target/src/main/java/org/jscsi/target/scsi/report/OneOpCode.java new file mode 100644 index 000000000..e1b36131c --- /dev/null +++ b/bundles/target/src/main/java/org/jscsi/target/scsi/report/OneOpCode.java @@ -0,0 +1,40 @@ +package org.jscsi.target.scsi.report; + + +import java.nio.ByteBuffer; + +import org.jscsi.target.scsi.IResponseData; + +/** + * Supported one_command parameter data format. + * + * @author CHEN Qingcan + */ +public final class OneOpCode implements IResponseData { + + private final int reqOpCode; + + /** + * @param reqOpCode requested operation code + */ + public OneOpCode (int reqOpCode) { + this.reqOpCode = reqOpCode; + // TODO determine whether supported by reqOpCode + } + + @Override + public void serialize (ByteBuffer out, int index) { + out.position (index); + out.put ((byte) 0); + out.put ((byte) 0b011); // The device server supports the requested command in conformance with a SCSI standard. + out.put ((byte) 0); + out.put ((byte) 1); // CDB size + out.put ((byte) reqOpCode); // CDB usage data + } + + @Override + public int size () { + return 5; + } + +} diff --git a/bundles/target/src/main/java/org/jscsi/target/util/ReadWrite.java b/bundles/target/src/main/java/org/jscsi/target/util/ReadWrite.java index 3294cb020..8f27126ae 100644 --- a/bundles/target/src/main/java/org/jscsi/target/util/ReadWrite.java +++ b/bundles/target/src/main/java/org/jscsi/target/util/ReadWrite.java @@ -2,12 +2,13 @@ import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * This utility class contains static methods for reading/writing integers of various lengths and character strings * from/to {@link ByteBuffer} objects and byte arrays. - * + * * @author Andreas Ergenzinger */ public final class ReadWrite { @@ -17,7 +18,7 @@ private ReadWrite() { /** * Reads a specified byte from a {@link ByteBuffer} and returns its value as an unsigned integer. - * + * * @param buffer the {@link ByteBuffer} containing the byte * @param start the index position of the byte in the {@link ByteBuffer} * @return the unsigned integer value of the byte @@ -29,7 +30,7 @@ public static final int readOneByteInt (ByteBuffer buffer, int start) { /** * Reads a specified byte from a byte array and returns its value as an unsigned integer. - * + * * @param array the array containing the byte * @param start the index position of the byte in the array * @return the unsigned integer value of the byte @@ -41,7 +42,7 @@ public static final int readOneByteInt (byte[] array, int start) { /** * Reads an unsigned 2-byte integer from two consecutive big-endian-ordered bytes of a {@link ByteBuffer} object and * returns the value. - * + * * @param buffer the {@link ByteBuffer} containing the bytes * @param start the index position of the most-significant byte * @return the unsigned value of the two-byte integer @@ -55,7 +56,7 @@ public static final int readTwoByteInt (ByteBuffer buffer, int start) { /** * Reads an unsigned 2-byte integer from two consecutive big-endian-ordered bytes of a byte array and returns the * value. - * + * * @param array the byte array containing the bytes * @param start the index position of the most-significant byte * @return the unsigned value of the two-byte integer @@ -67,7 +68,7 @@ public static final int readTwoByteInt (byte[] array, int start) { /** * Reads an unsigned 3-byte integer from three consecutive big-endian-ordered bytes of a {@link ByteBuffer} object * and returns the value. - * + * * @param buffer the {@link ByteBuffer} containing the bytes * @param start the index position of the most-significant byte * @return the unsigned value of the three-byte integer @@ -82,7 +83,7 @@ public static final int readThreeByteInt (ByteBuffer buffer, int start) { /** * Reads an unsigned 3-byte integer from three consecutive big-endian-ordered bytes of a byte array and returns the * value. - * + * * @param array the byte array containing the bytes * @param start the index position of the most-significant byte * @return the unsigned value of the three-byte integer @@ -94,7 +95,7 @@ public static final int readThreeByteInt (byte[] array, int start) { /** * Reads a (signed) 4-byte integer from four consecutive big-endian-ordered bytes of a {@link ByteBuffer} object and * returns the value. - * + * * @param buffer the {@link ByteBuffer} containing the bytes * @param start the index position of the most-significant byte * @return the value of the four-byte integer @@ -110,7 +111,7 @@ public static final int readFourByteInt (ByteBuffer buffer, int start) { /** * Reads a (signed) 4-byte integer from four consecutive big-endian-ordered bytes of a byte array and returns the * value. - * + * * @param array the byte array containing the bytes * @param start the index position of the most-significant byte * @return the unsigned value of the four-byte integer @@ -119,13 +120,25 @@ public static final int readFourByteInt (byte[] array, int start) { return ((array[start] & 255) << 24) | ((array[start + 1] & 255) << 16) | ((array[start + 2] & 255) << 8) | (array[start + 3] & 255); } + /** + * Reads a (signed) 8-byte integer from eight consecutive big-endian-ordered bytes of a {@link ByteBuffer} object and + * returns the value. + * + * @param buffer the {@link ByteBuffer} containing the bytes + * @param start the index position of the most-significant byte + * @return the value of the four-byte integer + */ + public static final long readEightByteInt (ByteBuffer buffer, int start) { + return buffer.order (ByteOrder.BIG_ENDIAN).getLong (start); + } + /** * Puts the characters in the passed String into an array of one or more ByteBuffers and returns it. *

* If the String does not end with a null character, one will be appended. If the String's length is larger than the * specified bufferSize, all but the last ByteBuffer will have capacity() = bufferSize, the last one * will contain the remaining String characters. - * + * * @param string the String to be put into the ByteBuffer * @param bufferSize the maximum size of the returned ByteBuffers * @return an array of ByteBuffers containing the passed String @@ -148,7 +161,7 @@ public static ByteBuffer[] stringToTextDataSegments (String string, int bufferSi /** * Puts the characters in the passed String into a ByteBuffer of equal length and returns it. - * + * * @param string any String * @return a ByteBuffer containing the characters of the passed String */ @@ -162,7 +175,7 @@ private static ByteBuffer stringToByteBuffer (final String string) { /** * Appends the content of a ProtocolDataUnit (text) data segment to a {@link StringBuilder}; - * + * * @param byteBuffer the PDU's data segment * @param stringBuilder the {@link StringBuilder} that will be extended */ @@ -174,9 +187,9 @@ public static final void appendTextDataSegmentToStringBuffer (final ByteBuffer b /** * Writes the given value to the buffer in big-endian format, with the index position of the most * significant byte being start. - * + * * To get the value back from the buffer, use readUnsignedInt. - * + * * @param value the integer to write to the ByteBuffer * @param buffer where the integer will be stored * @param start index of the most significant byte of the stored value @@ -191,7 +204,7 @@ public static final void writeInt (int value, final ByteBuffer buffer, int start /** * Returns the bytes in a {@link ByteBuffer} as a UTF-8 encoded {@link String}. - * + * * @param buffer a {@link ByteBuffer} containing UTF-8 encoded characters. * @return a String representation of the buffer's content */ @@ -202,7 +215,7 @@ public static String byteBufferToString (final ByteBuffer buffer) { /** * Splits the passed value into bytes and returns them in an array, in big-endian format. - * + * * @param value the long to split * @return byte representation of the parameter */ @@ -216,7 +229,7 @@ public static byte[] longToBytes (final long value) { /** * Writes the given value to the buffer in big-endian format, with the index position of the most * significant byte being index. - * + * * @param value the integer to write to the ByteBuffer * @param buffer where the integer will be stored * @param index index of the most significant byte of the stored value @@ -231,7 +244,7 @@ public static void writeLong (final ByteBuffer buffer, final long value, final i /** * Writes the two least-significant big-endian-ordered bytes of an integer the a specified position in a * {@link ByteBuffer}. - * + * * @param buffer where the bytes will be written * @param value the value to convert and copy * @param index the position of the most significant byte in the {@link ByteBuffer} @@ -245,7 +258,7 @@ public static void writeTwoByteInt (final ByteBuffer buffer, final int value, fi /** * Writes the three least-significant big-endian-ordered bytes of an integer the a specified position in a * {@link ByteBuffer}. - * + * * @param buffer where the bytes will be written * @param value the value to convert and copy * @param index the position of the most significant byte in the {@link ByteBuffer} @@ -261,7 +274,7 @@ public static void writeThreeByteInt (final ByteBuffer buffer, final int value, /** * Reads an unsigned 4-byte integer from four consecutive big-endian-ordered bytes of a {@link ByteBuffer} object * and returns the value. - * + * * @param buffer the {@link ByteBuffer} containing the bytes * @param start the index position of the most-significant byte * @return the value of the unsigned four-byte integer From 7acaa6f9c627b53c4fe573988ae07c69395a5e0c Mon Sep 17 00:00:00 2001 From: ActiveVolcano Date: Fri, 29 Jul 2022 16:05:44 +0800 Subject: [PATCH 6/7] Ignore javadoc plugin errors --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index d7fbb4a98..4d7c969d6 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,7 @@ maven-javadoc-plugin + 2.7 attach-sources From a637f235bd09c19b125fd8be701142ea04fd48c2 Mon Sep 17 00:00:00 2001 From: ActiveVolcano Date: Fri, 29 Jul 2022 16:17:39 +0800 Subject: [PATCH 7/7] How to build --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 0b3c17ea8..4ec022b14 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,16 @@ For further documentation and as an example, please refer to the examples in the * bundles: bundles containing the projects * pom.xml: Simple pom (yes we use Maven) +## Build +* jar only: +```bash +mvn -Dmaven.test.skip=true -Dmaven.source.skip=true -Dmaven.javadoc.skip=true clean package +``` +* jar, javadoc and sources: +```bash +mvn -Dmaven.test.skip=true -Pdoclint-java8-disable clean package +``` + ## License This work is released in the public domain under the BSD 3-clause license