package org.jscsi.target.settings.entry; import org.jscsi.target.TargetServer; import org.jscsi.target.settings.KeySet; import org.jscsi.target.settings.NegotiationStatus; import org.jscsi.target.settings.NegotiationType; import org.jscsi.target.settings.NumericalValueRange; import org.jscsi.target.settings.SingleNumericalValue; /** * An {@link Entry} sub-class used for negotiating integer parameters which * require the iSCSI initiator to offer an interval from which the target must * choose the final value. Thereby the <i>key=value</i> format differs from that * required by the {@link NumericalEntry} class, for which <i>value</i> is a * single integer. The <i>value</i> part expected by this class looks like <code>1024~2048</code>, however the * response <i>value</i> will again be a * single integer from the given range. * <p> * Currently this {@link Entry} sub-class is only used for two parameters - <code>IFMarkInt</code> and * <code>OFMarkInt</code>. However, since the jSCSI Target does not support stream markers ( * <code>IFMarker=No</code> and <code>OFMarker=No</code>), the correct response value to * <code>IFMarkInt</code> and <code>OFMarkInt</code> <i>keys</i> must be <code>Irrelevant</code>. This * behavior is part of the * {@link Entry#negotiate(org.jscsi.target.TargetServer, org.jscsi.parser.login.LoginStage, boolean, boolean, String, String, java.util.Collection)} * method, which will lead to correct responses without having to check for additional constraints (the * presence and <i>value</i> of <code>IFMarker</code> and <code>OFMarker</code> <i>key=value</i> pairs. * * @author Andreas Ergenzinger */ public final class NumericalRangeEntry extends Entry { /** * A {@link NumericalValueRange} specifying the boundaries into which any * RFC-conform <i>value</i> range proposed by the iSCSI initiator must fall. */ private final NumericalValueRange protocolValueRange; /** * This value will be the negotiation result, if it falls into the * <i>value</i> range proposed by the iSCSI initiator. */ private final int negotiationValue; /** * The {@link NumericalRangeEntry} constructor. * * @param keySet * contains all relevant keys * @param use * determines under which circumstances the parameter may be * negotiated * @param negotiationStatus * indicates whether there is a default value or if the parameter * must be negotiated * @param negotiationValue * the value the jSCSI Target would like to use * @param protocolValueRange * specifies the boundaries into which any RFC-conform * <i>value</i> range proposed by the iSCSI initiator must fall * @param defaultValue * the default value or <code>null</code> */ public NumericalRangeEntry(final KeySet keySet, final Use use, final NegotiationStatus negotiationStatus, final int negotiationValue, final NumericalValueRange protocolValueRange, final Object defaultValue) { super(keySet, NegotiationType.NEGOTIATED, use, negotiationStatus, defaultValue); this.negotiationValue = negotiationValue; this.protocolValueRange = protocolValueRange; } @Override protected boolean inProtocolValueRange(Object values) { // receives a NumericalValueRange return protocolValueRange.contains((NumericalValueRange)values); } @Override protected Object parseOffer(TargetServer target, String values) { // expected format: "1234~5678" NumericalValueRange range = NumericalValueRange.parseNumericalValueRange(values); if (range == null && target.getConfig().getAllowSloppyNegotiation()) { /* * The format was violated. * * The jSCSI Initiator sends "IFMarkInt=2048" and "OFMarkInt=2048", * not ranges. * * If values is at least a number we will fix this. */ final SingleNumericalValue singleValue = SingleNumericalValue.parseSingleNumericValue(values); if (singleValue != null) { range = NumericalValueRange.create(singleValue.getValue(),// min singleValue.getValue());// max } } return range; } @Override protected void processDeclaration(Object values) { // there are no declarations, see constructor } @Override protected String processNegotiation(Object values) { // receives a NumericalValueRange final NumericalValueRange range = (NumericalValueRange)values; // accept if negotiatedValue in initiator offer, else reject if (range.contains(negotiationValue)) { value = negotiationValue; return value.toString(); } // else value = null; return null; } @Override public Integer getIntegerValue() { return (Integer)value; } @Override public Entry copy() { final NumericalRangeEntry e = new NumericalRangeEntry(keySet, use, negotiationStatus, negotiationValue, protocolValueRange, (Integer)value); e.alreadyNegotiated = this.alreadyNegotiated; return e; } }