0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.drda.DDMReader
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.drda;
0023:
0024: import org.apache.derby.iapi.services.sanity.SanityManager;
0025: import java.io.IOException;
0026: import java.io.InputStream;
0027: import java.io.ByteArrayOutputStream;
0028: import java.io.ByteArrayInputStream;
0029: import java.math.BigDecimal;
0030:
0031: /**
0032: The DDMReader is used to read DRDA protocol. DRDA Protocol is divided into
0033: three layers corresponding to the DDM three-tier architecture. For each layer,
0034: their is a DSS (Data Stream Structure) defined.
0035: Layer A Communications management services
0036: Layer B Agent services
0037: Layer C Data management services
0038: <P>
0039: At layer A are request, reply and data correlation, structure chaining,
0040: continuation or termination of chains when errors are detected, interleaving
0041: and multi-leaving request, reply, and data DSSs for multitasking environments.
0042: For TCP/IP, the format of the DDM envelope is
0043: 2 bytes Length of the data
0044: 1 byte 'D0' - indicates DDM data
0045: 1 byte DDM format byte(DSSFMT) - type of DSS(RQSDSS,RPYDSS), whether it is
0046: chained, information about the next chained DSS
0047: 2 bytes request correlation identifier
0048: <P>
0049: The correlation identifier ties together a request, the request data and the
0050: reply. In a chained DSS, each request has a correlation identifier which
0051: is higher than the previous request (all correlation identifiers must
0052: be greater than 0).
0053: <P>
0054: At layer B are object mapping, object validation and command routing.
0055: Layer B objects with data 5 bytes less than 32K bytes consist of
0056: 2 bytes Length
0057: 2 bytes Type of the object (code point)
0058: Object data
0059: Object data is either SCALAR or COLLECTION data. Scalar data consists of
0060: a string of bytes formatted as the class description of the object required.
0061: Collections consist of a set of objects in which the entries in the collection
0062: are nested within the length/ code point of the collection.
0063: <P>
0064: Layer B objects with data >=32763 bytes long format is
0065: 2 bytes Length - length of class, length, and extended total length fields
0066: (high order bit set, indicating >=32763)
0067: 2 bytes Type of the object (code point)
0068: n bytes Extended total length - length of the object
0069: (n = Length - 4)
0070: Object data
0071: <P>
0072: At layer C are services each class of DDM object provides.
0073:
0074: |-------------------------------------------|
0075: Layer C | Specific | Specific | Specific |
0076: | Commands | Replies | Scalars and |
0077: | and their | and their | Collections |
0078: |-------------------------------------------|----------------|
0079: Layer B | Commands | Reply | Scalars and | Communications |
0080: | | Messages | Collections | |
0081: |-----------|---------------|---------------|----------------|
0082: Layer A | RQSDSS | RPYDSS | OBJDSS | CMNDSS |
0083: | | | | Mapped Data |
0084: |-----------|---------------|---------------|----------------|
0085: | DDM Data Stream Structures |
0086: |------------------------------------------------------------|
0087:
0088: DSS's may be chained so that more than one can be transmitted at a time
0089: to improve performance.
0090: For more details, see DRDA Volume 3 (Distributed Data Management(DDM)
0091: Architecture (DDS definition)
0092: */
0093: class DDMReader {
0094: private final static int DEFAULT_BUFFER_SIZE = 32767;
0095: private final static int MAX_MARKS_NESTING = 10;
0096: private final static int NO_CODEPOINT = -1;
0097: private final static int EMPTY_STACK = -1;
0098: private final static boolean ADJUST_LENGTHS = true;
0099: private final static boolean NO_ADJUST_LENGTHS = false;
0100: private final static long MAX_EXTDTA_SIZE = Long.MAX_VALUE;
0101: private static boolean internalTrace = true;
0102:
0103: // magnitude represented in an int array, used in BigDecimal conversion
0104: private static final int[][] tenRadixMagnitude = { { 0x3b9aca00 }, // 10^9
0105: { 0x0de0b6b3, 0xa7640000 }, // 10^18
0106: { 0x033b2e3c, 0x9fd0803c, 0xe8000000 }, // 10^27
0107: };
0108:
0109: private DRDAConnThread agent;
0110: private CcsidManager ccsidManager;
0111:
0112: // data buffer
0113: private byte[] buffer;
0114: private int pos;
0115: private int count;
0116:
0117: // DDM object collection
0118: // top of stack
0119: private int topDdmCollectionStack;
0120: // length of each object in the stack
0121: private long[] ddmCollectionLenStack;
0122:
0123: // DDM object length
0124: private long ddmScalarLen;
0125:
0126: // DSS Length
0127: private int dssLength;
0128:
0129: // DSS is larger than 32762 (continuation bit is set) so DSS is continued
0130: private boolean dssIsContinued;
0131:
0132: private boolean terminateChainOnErr;
0133:
0134: // next DSS in the chain has the same correlator
0135: private boolean dssIsChainedWithSameID;
0136:
0137: // next DSS in the chain has a different correlator
0138: private boolean dssIsChainedWithDiffID;
0139:
0140: // correlation id for the current DSS
0141: private int dssCorrelationID;
0142:
0143: // previous corelation id
0144: private int prevCorrelationID;
0145:
0146: // current server codepoint
0147: private int svrcod;
0148:
0149: // trace object of the associated session
0150: private DssTrace dssTrace;
0151:
0152: // input stream
0153: private InputStream inputStream;
0154:
0155: // constructor
0156: DDMReader(DRDAConnThread agent, DssTrace dssTrace) {
0157: buffer = new byte[DEFAULT_BUFFER_SIZE];
0158: ddmCollectionLenStack = new long[MAX_MARKS_NESTING];
0159: initialize(agent, dssTrace);
0160: }
0161:
0162: /**
0163: * This constructor is used for testing the protocol
0164: * It is used by TestProto to read the protocol returned by the
0165: * server
0166: */
0167: DDMReader(CcsidManager ccsidManager, InputStream inputStream) {
0168: buffer = new byte[DEFAULT_BUFFER_SIZE];
0169: ddmCollectionLenStack = new long[MAX_MARKS_NESTING];
0170: this .ccsidManager = ccsidManager;
0171: this .inputStream = inputStream;
0172: initialize(null, null);
0173: // turn off tracing
0174: internalTrace = false;
0175: }
0176:
0177: /**
0178: * This initializer is used for testing the protocol
0179: * It is used by TestProto for the reader it uses
0180: */
0181: protected void initialize(InputStream inputStream) {
0182: this .inputStream = inputStream;
0183: initialize(null, null);
0184: }
0185:
0186: /**
0187: * Initialize values for this session, the reader is reused so we need to
0188: * set null and 0 values
0189: */
0190: protected void initialize(DRDAConnThread agent, DssTrace dssTrace) {
0191: this .agent = agent;
0192: if (agent != null) {
0193: ccsidManager = agent.ccsidManager;
0194: inputStream = agent.getInputStream();
0195: }
0196: topDdmCollectionStack = EMPTY_STACK;
0197: svrcod = 0;
0198: pos = 0;
0199: count = 0;
0200: ddmScalarLen = 0;
0201: dssLength = 0;
0202: prevCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;
0203: dssCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;
0204: this .dssTrace = dssTrace;
0205: }
0206:
0207: protected boolean terminateChainOnErr() {
0208: return terminateChainOnErr;
0209: }
0210:
0211: /**
0212: * Next DSS has same correlator as current DSS
0213: *
0214: * @return true if next DSS has the same correlator as current DSS
0215: */
0216: protected boolean isChainedWithSameID() {
0217: return dssIsChainedWithSameID;
0218: }
0219:
0220: /**
0221: * Next DSS has different correlator than current DSS
0222: *
0223: * @return true if next DSS has a different correlator than current DSS
0224: */
0225: protected boolean isChainedWithDiffID() {
0226: return dssIsChainedWithDiffID;
0227: }
0228:
0229: /**
0230: * Length of current DDM object
0231: *
0232: * @return length of DDM object
0233: */
0234: protected long getDdmLength() {
0235: return ddmScalarLen;
0236: }
0237:
0238: /**
0239: * Is there more in this DDM object
0240: *
0241: * @return true if DDM length is > 0
0242: */
0243: protected boolean moreDdmData() {
0244: return ddmScalarLen > 0;
0245: }
0246:
0247: /**
0248: * Is there more in this DDS object
0249: *
0250: * @return true if DDS length is > 0
0251: */
0252: protected boolean moreDssData() {
0253: return dssLength > 0;
0254: }
0255:
0256: /**
0257: * Is there more data in the buffer
0258: *
0259: * @return true if there is more data in the buffer
0260: */
0261: protected boolean moreData() {
0262: return (pos - count) > 0;
0263: }
0264:
0265: /**
0266: * Check for the command protocol
0267: *
0268: * @return true if this is a command; false otherwise
0269: *
0270: * @exception DRDProtocolException
0271: */
0272: protected boolean isCmd() throws DRDAProtocolException,
0273: java.io.UnsupportedEncodingException {
0274: ensureALayerDataInBuffer(4);
0275: String val = new String(buffer, 0, 4,
0276: NetworkServerControlImpl.DEFAULT_ENCODING);
0277: return NetworkServerControlImpl.isCmd(val);
0278: }
0279:
0280: /**
0281: * Read DSS header
0282: * DSS Header format is
0283: * 2 bytes - length
0284: * 1 byte - 'D0' - indicates DDM data
0285: * 1 byte - DSS format
0286: * |---|---------|----------|
0287: * | 0 | flags | type |
0288: * |---|---------|----------|
0289: * | 0 | 1 2 3 | 4 5 6 7 |
0290: * |---|---------|----------|
0291: * bit 0 - '0'
0292: * bit 1 - '0' - unchained, '1' - chained
0293: * bit 2 - '0' - do not continue on error, '1' - continue on error
0294: * bit 3 - '0' - next DSS has different correlator, '1' - next DSS has
0295: * same correlator
0296: * type - 1 - Request DSS
0297: * - 2 - Reply DSS
0298: * - 3 - Object DSS
0299: * - 4 - Communications DSS
0300: * - 5 - Request DSS where no reply is expected
0301: * 2 bytes - request correlation id
0302: *
0303: * @exception DRDProtocolException
0304: */
0305: protected int readDssHeader() throws DRDAProtocolException {
0306: ensureALayerDataInBuffer(6);
0307:
0308: // read out the DSS length
0309: dssLength = ((buffer[pos] & 0xff) << 8)
0310: + ((buffer[pos + 1] & 0xff) << 0);
0311: pos += 2;
0312: // check for the continuation bit and update length as needed.
0313: if ((dssLength & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) {
0314: dssLength = DssConstants.MAX_DSS_LENGTH;
0315: dssIsContinued = true;
0316: } else {
0317: dssIsContinued = false;
0318: }
0319:
0320: if (dssLength < 6)
0321: agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_LESS_THAN_6,
0322: DRDAProtocolException.NO_CODPNT_ARG);
0323:
0324: // If the GDS id is not valid, or
0325: // if the reply is not an RQSDSS nor
0326: // a OBJDSS, then throw an exception.
0327:
0328: if ((buffer[pos++] & 0xff) != DssConstants.DSS_ID)
0329: agent.throwSyntaxrm(CodePoint.SYNERRCD_CBYTE_NOT_D0,
0330: DRDAProtocolException.NO_CODPNT_ARG);
0331:
0332: int gdsFormatter = buffer[pos++] & 0xff;
0333:
0334: if (((gdsFormatter & 0x0F) != DssConstants.DSSFMT_RQSDSS)
0335: && ((gdsFormatter & 0x0F) != DssConstants.DSSFMT_OBJDSS)) {
0336: agent.throwSyntaxrm(CodePoint.SYNERRCD_FBYTE_NOT_SUPPORTED,
0337: DRDAProtocolException.NO_CODPNT_ARG);
0338: }
0339:
0340: // Determine if the current DSS is chained with the
0341: // next DSS, with the same or different request ID.
0342: if ((gdsFormatter & DssConstants.DSSCHAIN) == DssConstants.DSSCHAIN) { // on indicates structure chained to next structure
0343: if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) == DssConstants.DSSCHAIN_SAME_ID) {
0344: dssIsChainedWithSameID = true;
0345: dssIsChainedWithDiffID = false;
0346: } else {
0347: dssIsChainedWithSameID = false;
0348: dssIsChainedWithDiffID = true;
0349: }
0350: if ((gdsFormatter & DssConstants.DSSCHAIN_ERROR_CONTINUE) == DssConstants.DSSCHAIN_ERROR_CONTINUE)
0351: terminateChainOnErr = false;
0352: else
0353: terminateChainOnErr = true;
0354: } else {
0355: // chaining bit not b'1', make sure DSSFMT same id not b'1'
0356: if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) == DssConstants.DSSCHAIN_SAME_ID) { // Next DSS can not have same correlator
0357: agent
0358: .throwSyntaxrm(
0359: CodePoint.SYNERRCD_CHAIN_OFF_SAME_NEXT_CORRELATOR,
0360: DRDAProtocolException.NO_CODPNT_ARG);
0361: }
0362: // chaining bit not b'1', make sure no error continuation
0363: if ((gdsFormatter & DssConstants.DSSCHAIN_ERROR_CONTINUE) == DssConstants.DSSCHAIN_ERROR_CONTINUE) { // must be 'do not continue on error'
0364: agent.throwSyntaxrm(
0365: CodePoint.SYNERRCD_CHAIN_OFF_ERROR_CONTINUE,
0366: DRDAProtocolException.NO_CODPNT_ARG);
0367: }
0368:
0369: dssIsChainedWithSameID = false;
0370: dssIsChainedWithDiffID = false;
0371: }
0372:
0373: dssCorrelationID = ((buffer[pos] & 0xff) << 8)
0374: + ((buffer[pos + 1] & 0xff) << 0);
0375: pos += 2;
0376: if (SanityManager.DEBUG)
0377: trace("dssLength = " + dssLength + " correlationID = "
0378: + dssCorrelationID);
0379:
0380: //check that correlationID is the same as previous
0381: if (prevCorrelationID != DssConstants.CORRELATION_ID_UNKNOWN
0382: && dssCorrelationID != prevCorrelationID) {
0383: agent.throwSyntaxrm(
0384: CodePoint.SYNERRCD_CHAIN_OFF_ERROR_CONTINUE,
0385: DRDAProtocolException.NO_CODPNT_ARG);
0386: }
0387:
0388: // set up previous correlation id to check that next DSS is correctly
0389: // formatted
0390: if (dssIsChainedWithSameID)
0391: prevCorrelationID = dssCorrelationID;
0392: else
0393: prevCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;
0394:
0395: dssLength -= 6;
0396:
0397: return dssCorrelationID;
0398: }
0399:
0400: /**
0401: * Read Reply DSS
0402: * This is used in testing the protocol. We shouldn't see a reply
0403: * DSS when we are servicing DRDA commands
0404: *
0405: * @exception DRDProtocolException
0406: */
0407: protected void readReplyDss() throws DRDAProtocolException {
0408: ensureALayerDataInBuffer(6);
0409:
0410: // read out the DSS length
0411: dssLength = ((buffer[pos++] & 0xff) << 8)
0412: + ((buffer[pos++] & 0xff) << 0);
0413:
0414: // check for the continuation bit and update length as needed.
0415: if ((dssLength & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) {
0416: dssLength = DssConstants.MAX_DSS_LENGTH;
0417: dssIsContinued = true;
0418: } else {
0419: dssIsContinued = false;
0420: }
0421:
0422: if (dssLength < 6)
0423: agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_LESS_THAN_6,
0424: DRDAProtocolException.NO_CODPNT_ARG);
0425:
0426: // If the GDS id is not valid, throw exception
0427:
0428: if ((buffer[pos++] & 0xff) != DssConstants.DSS_ID)
0429: agent.throwSyntaxrm(CodePoint.SYNERRCD_CBYTE_NOT_D0,
0430: DRDAProtocolException.NO_CODPNT_ARG);
0431:
0432: int gdsFormatter = buffer[pos++] & 0xff;
0433:
0434: // Determine if the current DSS is chained with the
0435: // next DSS, with the same or different request ID.
0436: if ((gdsFormatter & DssConstants.DSSCHAIN) == DssConstants.DSSCHAIN) { // on indicates structure chained to next structure
0437: if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) == DssConstants.DSSCHAIN_SAME_ID) {
0438: dssIsChainedWithSameID = true;
0439: dssIsChainedWithDiffID = false;
0440: } else {
0441: dssIsChainedWithSameID = false;
0442: dssIsChainedWithDiffID = true;
0443: }
0444: } else {
0445: dssIsChainedWithSameID = false;
0446: dssIsChainedWithDiffID = false;
0447: }
0448:
0449: dssCorrelationID = ((buffer[pos++] & 0xff) << 8)
0450: + ((buffer[pos++] & 0xff) << 0);
0451:
0452: if (SanityManager.DEBUG)
0453: trace("dssLength = " + dssLength + " correlationID = "
0454: + dssCorrelationID);
0455:
0456: dssLength -= 6;
0457:
0458: }
0459:
0460: /**
0461: * Read the DDM Length and CodePoint
0462: *
0463: * @return - returns codepoint
0464: *
0465: * @exception DRDProtocolException
0466: */
0467: protected int readLengthAndCodePoint() throws DRDAProtocolException {
0468: ensureBLayerDataInBuffer(4, NO_ADJUST_LENGTHS);
0469:
0470: ddmScalarLen = readCodePoint();
0471: int codePoint = readCodePoint();
0472:
0473: if (SanityManager.DEBUG)
0474: trace("length = " + ddmScalarLen + " codepoint = "
0475: + java.lang.Integer.toHexString(codePoint));
0476: // SYNERRCD 0x0D - Object code point index not supported.
0477: // the object codepoint index will not be checked here since
0478: // the parse methods will catch any incorrect/unexpected codepoint values
0479: // and report them as unsupported objects or parameters.
0480:
0481: // Check if this DDM has extended length field
0482: if ((ddmScalarLen & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) {
0483: int numberOfExtendedLenBytes = ((int) ddmScalarLen - DssConstants.CONTINUATION_BIT) - 4;
0484: int adjustSize = 0;
0485: ensureBLayerDataInBuffer(numberOfExtendedLenBytes,
0486: NO_ADJUST_LENGTHS);
0487: switch (numberOfExtendedLenBytes) {
0488: case 8:
0489: ddmScalarLen = ((buffer[pos++] & 0xff) << 56)
0490: + ((buffer[pos++] & 0xff) << 48)
0491: + ((buffer[pos++] & 0xff) << 40)
0492: + ((buffer[pos++] & 0xff) << 32)
0493: + ((buffer[pos++] & 0xff) << 24)
0494: + ((buffer[pos++] & 0xff) << 16)
0495: + ((buffer[pos++] & 0xff) << 8)
0496: + ((buffer[pos++] & 0xff) << 0);
0497: adjustSize = 12;
0498: break;
0499: case 6:
0500: ddmScalarLen = ((buffer[pos++] & 0xff) << 40)
0501: + ((buffer[pos++] & 0xff) << 32)
0502: + ((buffer[pos++] & 0xff) << 24)
0503: + ((buffer[pos++] & 0xff) << 16)
0504: + ((buffer[pos++] & 0xff) << 8)
0505: + ((buffer[pos++] & 0xff) << 0);
0506: adjustSize = 10;
0507: break;
0508: case 4:
0509: ddmScalarLen = ((buffer[pos++] & 0xff) << 24)
0510: + ((buffer[pos++] & 0xff) << 16)
0511: + ((buffer[pos++] & 0xff) << 8)
0512: + ((buffer[pos++] & 0xff) << 0);
0513: adjustSize = 8;
0514: break;
0515: default:
0516: agent.throwSyntaxrm(
0517: CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN,
0518: DRDAProtocolException.NO_CODPNT_ARG);
0519: }
0520:
0521: // adjust the lengths here. this is a special case since the
0522: // extended length bytes do not include their own length.
0523: for (int i = 0; i <= topDdmCollectionStack; i++) {
0524: ddmCollectionLenStack[i] -= adjustSize;
0525: }
0526: dssLength -= adjustSize;
0527: } else {
0528: if (ddmScalarLen < 4)
0529: agent.throwSyntaxrm(
0530: CodePoint.SYNERRCD_OBJ_LEN_LESS_THAN_4,
0531: DRDAProtocolException.NO_CODPNT_ARG);
0532: adjustLengths(4);
0533: }
0534: return codePoint;
0535: }
0536:
0537: /**
0538: * Read the CodePoint
0539: *
0540: * @return - returns codepoint
0541: */
0542: protected int readCodePoint() {
0543: return (((buffer[pos++] & 0xff) << 8) + ((buffer[pos++] & 0xff) << 0));
0544: }
0545:
0546: /**
0547: * Push DDM Length on to collection stack
0548: */
0549: protected void markCollection() {
0550: ddmCollectionLenStack[++topDdmCollectionStack] = ddmScalarLen;
0551: ddmScalarLen = 0;
0552: }
0553:
0554: /**
0555: * Get the next CodePoint from a collection
0556: * @return NO_CODEPOINT if collection stack is empty or remaining length is
0557: * 0; otherwise, read length and code point
0558: *
0559: * @exception DRDProtocolException
0560: */
0561: protected int getCodePoint() throws DRDAProtocolException {
0562: if (topDdmCollectionStack == EMPTY_STACK) {
0563: return NO_CODEPOINT;
0564: } else {
0565: // if the collecion is exhausted then return NO_CODEPOINT
0566: if (ddmCollectionLenStack[topDdmCollectionStack] == 0) {
0567: // done with this collection so remove it's length from the stack
0568: ddmCollectionLenStack[topDdmCollectionStack--] = 0;
0569: return NO_CODEPOINT;
0570: } else {
0571: return readLengthAndCodePoint();
0572: }
0573: }
0574: }
0575:
0576: /**
0577: * Get the next CodePoint from a collection and check that it matches the specified
0578: * CodePoint
0579: * @param codePointCheck - codePoint to check against
0580: * @return codePoint
0581: *
0582: * @exception DRDProtocolException
0583: */
0584: protected int getCodePoint(int codePointCheck)
0585: throws DRDAProtocolException {
0586: int codePoint = getCodePoint();
0587: if (codePoint != codePointCheck)
0588: agent.missingCodePoint(codePoint);
0589: return codePoint;
0590: }
0591:
0592: /**
0593: * The following routines read different types from the input stream
0594: * Data can be in network order or platform order depending on whether the
0595: * data is part of the protocol or data being received
0596: * The platform is determined by EXCSAT protocol
0597: */
0598:
0599: /**
0600: * Read byte value
0601: * @return value
0602: *
0603: * @exception DRDProtocolException
0604: */
0605: protected byte readByte() throws DRDAProtocolException {
0606: ensureBLayerDataInBuffer(1, ADJUST_LENGTHS);
0607: return buffer[pos++];
0608: }
0609:
0610: /**
0611: * Read byte value and mask out high order bytes before returning
0612: * @return value
0613: */
0614: protected int readUnsignedByte() throws DRDAProtocolException {
0615: ensureBLayerDataInBuffer(1, ADJUST_LENGTHS);
0616: return (int) (buffer[pos++] & 0xff);
0617: }
0618:
0619: /**
0620: * Read network short value
0621: * @return value
0622: *
0623: * @exception DRDProtocolException
0624: */
0625: protected int readNetworkShort() throws DRDAProtocolException {
0626: ensureBLayerDataInBuffer(2, ADJUST_LENGTHS);
0627: return ((buffer[pos++] & 0xff) << 8)
0628: + ((buffer[pos++] & 0xff) << 0);
0629: }
0630:
0631: /**
0632: * Read signed network short value
0633: * @return value
0634: *
0635: * @exception DRDProtocolException
0636: */
0637: protected int readSignedNetworkShort() throws DRDAProtocolException {
0638: ensureBLayerDataInBuffer(2, ADJUST_LENGTHS);
0639: return (short) (((buffer[pos++] & 0xff) << 8) + ((buffer[pos++] & 0xff) << 0));
0640: }
0641:
0642: /**
0643: * Read platform short value
0644: * @return value
0645: *
0646: * @exception DRDProtocolException
0647: */
0648: protected short readShort(int byteOrder)
0649: throws DRDAProtocolException {
0650: ensureBLayerDataInBuffer(2, ADJUST_LENGTHS);
0651: short s = SignedBinary.getShort(buffer, pos, byteOrder);
0652:
0653: pos += 2;
0654:
0655: return s;
0656: }
0657:
0658: /**
0659: * Read network int value
0660: * @return value
0661: *
0662: * @exception DRDProtocolException
0663: */
0664: protected int readNetworkInt() throws DRDAProtocolException {
0665: ensureBLayerDataInBuffer(4, ADJUST_LENGTHS);
0666: return ((buffer[pos++] & 0xff) << 24)
0667: + ((buffer[pos++] & 0xff) << 16)
0668: + ((buffer[pos++] & 0xff) << 8)
0669: + ((buffer[pos++] & 0xff) << 0);
0670: }
0671:
0672: /**
0673: * Read platform int value
0674: * @return value
0675: *
0676: * @exception DRDProtocolException
0677: */
0678: protected int readInt(int byteOrder) throws DRDAProtocolException {
0679: ensureBLayerDataInBuffer(4, ADJUST_LENGTHS);
0680: int i = SignedBinary.getInt(buffer, pos, byteOrder);
0681:
0682: pos += 4;
0683:
0684: return i;
0685: }
0686:
0687: /**
0688: * Read network long value
0689: * @return value
0690: *
0691: * @exception DRDProtocolException
0692: */
0693: protected long readNetworkLong() throws DRDAProtocolException {
0694: ensureBLayerDataInBuffer(8, ADJUST_LENGTHS);
0695:
0696: return ((buffer[pos++] & 0xffL) << 56)
0697: + ((buffer[pos++] & 0xffL) << 48)
0698: + ((buffer[pos++] & 0xffL) << 40)
0699: + ((buffer[pos++] & 0xffL) << 32)
0700: + ((buffer[pos++] & 0xffL) << 24)
0701: + ((buffer[pos++] & 0xffL) << 16)
0702: + ((buffer[pos++] & 0xffL) << 8)
0703: + ((buffer[pos++] & 0xffL) << 0);
0704: }
0705:
0706: /**
0707: * Read network six byte value and put it in a long v
0708: * @return value
0709: *
0710: * @exception DRDProtocolException
0711: */
0712: protected long readNetworkSixByteLong()
0713: throws DRDAProtocolException {
0714: ensureBLayerDataInBuffer(6, ADJUST_LENGTHS);
0715:
0716: return (((buffer[pos++] & 0xffL) << 40)
0717: + ((buffer[pos++] & 0xffL) << 32)
0718: + ((buffer[pos++] & 0xffL) << 24)
0719: + ((buffer[pos++] & 0xffL) << 16)
0720: + ((buffer[pos++] & 0xffL) << 8) + ((buffer[pos++] & 0xffL) << 0));
0721: }
0722:
0723: /**
0724: * Read platform long value
0725: * @return value
0726: *
0727: * @exception DRDProtocolException
0728: */
0729: protected long readLong(int byteOrder) throws DRDAProtocolException {
0730: ensureBLayerDataInBuffer(8, ADJUST_LENGTHS);
0731: long l = SignedBinary.getLong(buffer, pos, byteOrder);
0732:
0733: pos += 8;
0734:
0735: return l;
0736: }
0737:
0738: /**
0739: * Read platform float value
0740: * @return value
0741: *
0742: * @exception DRDProtocolException
0743: */
0744: protected float readFloat(int byteOrder)
0745: throws DRDAProtocolException {
0746: return Float.intBitsToFloat(readInt(byteOrder));
0747: }
0748:
0749: /**
0750: * Read platform double value
0751: * @return value
0752: *
0753: * @exception DRDProtocolException
0754: */
0755: protected double readDouble(int byteOrder)
0756: throws DRDAProtocolException {
0757: return Double.longBitsToDouble(readLong(byteOrder));
0758: }
0759:
0760: /**
0761: * Read a BigDecimal value
0762: * @param precision of the BigDecimal
0763: * @param scale of the BigDecimal
0764: * @return value
0765: *
0766: * @exception DRDProtocolException
0767: */
0768: protected BigDecimal readBigDecimal(int precision, int scale)
0769: throws DRDAProtocolException {
0770: // The byte-length of a packed decimal with precision p is always p/2 + 1
0771: int length = precision / 2 + 1;
0772:
0773: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
0774:
0775: // check for sign.
0776: int signum;
0777: if ((buffer[pos + length - 1] & 0x0F) == 0x0D)
0778: signum = -1;
0779: else
0780: signum = 1;
0781:
0782: if (precision <= 9) {
0783: // can be handled by int without overflow.
0784: int value = packedNybblesToInt(buffer, pos, 0,
0785: length * 2 - 1);
0786:
0787: // convert value to a byte array of magnitude.
0788: byte[] magnitude = new byte[4];
0789: magnitude[0] = (byte) (value >>> 24);
0790: magnitude[1] = (byte) (value >>> 16);
0791: magnitude[2] = (byte) (value >>> 8);
0792: magnitude[3] = (byte) (value);
0793:
0794: pos += length;
0795: return new java.math.BigDecimal(new java.math.BigInteger(
0796: signum, magnitude), scale);
0797: } else if (precision <= 18) {
0798: // can be handled by long without overflow.
0799: long value = packedNybblesToLong(buffer, pos, 0,
0800: length * 2 - 1);
0801:
0802: // convert value to a byte array of magnitude.
0803: byte[] magnitude = new byte[8];
0804: magnitude[0] = (byte) (value >>> 56);
0805: magnitude[1] = (byte) (value >>> 48);
0806: magnitude[2] = (byte) (value >>> 40);
0807: magnitude[3] = (byte) (value >>> 32);
0808: magnitude[4] = (byte) (value >>> 24);
0809: magnitude[5] = (byte) (value >>> 16);
0810: magnitude[6] = (byte) (value >>> 8);
0811: magnitude[7] = (byte) (value);
0812:
0813: pos += length;
0814: return new java.math.BigDecimal(new java.math.BigInteger(
0815: signum, magnitude), scale);
0816: } else if (precision <= 27) {
0817: // get the value of last 9 digits (5 bytes).
0818: int lo = packedNybblesToInt(buffer, pos, (length - 5) * 2,
0819: 9);
0820: // get the value of another 9 digits (5 bytes).
0821: int me = packedNybblesToInt(buffer, pos,
0822: (length - 10) * 2 + 1, 9);
0823: // get the value of the rest digits.
0824: int hi = packedNybblesToInt(buffer, pos, 0,
0825: (length - 10) * 2 + 1);
0826:
0827: // compute the int array of magnitude.
0828: int[] value = computeMagnitude(new int[] { hi, me, lo });
0829:
0830: // convert value to a byte array of magnitude.
0831: byte[] magnitude = new byte[12];
0832: magnitude[0] = (byte) (value[0] >>> 24);
0833: magnitude[1] = (byte) (value[0] >>> 16);
0834: magnitude[2] = (byte) (value[0] >>> 8);
0835: magnitude[3] = (byte) (value[0]);
0836: magnitude[4] = (byte) (value[1] >>> 24);
0837: magnitude[5] = (byte) (value[1] >>> 16);
0838: magnitude[6] = (byte) (value[1] >>> 8);
0839: magnitude[7] = (byte) (value[1]);
0840: magnitude[8] = (byte) (value[2] >>> 24);
0841: magnitude[9] = (byte) (value[2] >>> 16);
0842: magnitude[10] = (byte) (value[2] >>> 8);
0843: magnitude[11] = (byte) (value[2]);
0844:
0845: pos += length;
0846: return new java.math.BigDecimal(new java.math.BigInteger(
0847: signum, magnitude), scale);
0848: } else if (precision <= 31) {
0849: // get the value of last 9 digits (5 bytes).
0850: int lo = packedNybblesToInt(buffer, pos, (length - 5) * 2,
0851: 9);
0852: // get the value of another 9 digits (5 bytes).
0853: int meLo = packedNybblesToInt(buffer, pos,
0854: (length - 10) * 2 + 1, 9);
0855: // get the value of another 9 digits (5 bytes).
0856: int meHi = packedNybblesToInt(buffer, pos,
0857: (length - 14) * 2, 9);
0858: // get the value of the rest digits.
0859: int hi = packedNybblesToInt(buffer, pos, 0,
0860: (length - 14) * 2);
0861:
0862: // compute the int array of magnitude.
0863: int[] value = computeMagnitude(new int[] { hi, meHi, meLo,
0864: lo });
0865:
0866: // convert value to a byte array of magnitude.
0867: byte[] magnitude = new byte[16];
0868: magnitude[0] = (byte) (value[0] >>> 24);
0869: magnitude[1] = (byte) (value[0] >>> 16);
0870: magnitude[2] = (byte) (value[0] >>> 8);
0871: magnitude[3] = (byte) (value[0]);
0872: magnitude[4] = (byte) (value[1] >>> 24);
0873: magnitude[5] = (byte) (value[1] >>> 16);
0874: magnitude[6] = (byte) (value[1] >>> 8);
0875: magnitude[7] = (byte) (value[1]);
0876: magnitude[8] = (byte) (value[2] >>> 24);
0877: magnitude[9] = (byte) (value[2] >>> 16);
0878: magnitude[10] = (byte) (value[2] >>> 8);
0879: magnitude[11] = (byte) (value[2]);
0880: magnitude[12] = (byte) (value[3] >>> 24);
0881: magnitude[13] = (byte) (value[3] >>> 16);
0882: magnitude[14] = (byte) (value[3] >>> 8);
0883: magnitude[15] = (byte) (value[3]);
0884:
0885: pos += length;
0886: return new java.math.BigDecimal(new java.math.BigInteger(
0887: signum, magnitude), scale);
0888: } else {
0889: pos += length;
0890: // throw an exception here if nibbles is greater than 31
0891: throw new java.lang.IllegalArgumentException(
0892: "Decimal may only be up to 31 digits!");
0893: }
0894: }
0895:
0896: byte[] getExtData(boolean checkNullability)
0897: throws DRDAProtocolException {
0898: return getExtData(ddmScalarLen, checkNullability);
0899: }
0900:
0901: /**
0902: * Creates an InputStream which can stream EXTDTA objects.
0903: * The InputStream uses this DDMReader to read data from network. The
0904: * DDMReader should not be used before all data in the stream has been read.
0905: * @param checkNullability used to check if the stream is null. If it is
0906: * null, this method returns null
0907: * @return EXTDTAReaderInputStream object which can be passed to prepared
0908: * statement as a binary stream.
0909: * @exception DRDAProtocolException standard DRDA protocol exception
0910: */
0911: EXTDTAReaderInputStream getEXTDTAReaderInputStream(
0912: final boolean checkNullability)
0913: throws DRDAProtocolException {
0914: if (checkNullability && isEXTDTANull()) {
0915: return null;
0916: } else {
0917: return new EXTDTAReaderInputStream(this );
0918: }
0919: }
0920:
0921: /**
0922: * This method is used by EXTDTAReaderInputStream to read the first chunk
0923: * of data.
0924: * @param desiredLength the desired length of chunk
0925: * @exception DRDAProtocolException standard DRDA protocol exception
0926: */
0927: ByteArrayInputStream readLOBInitStream(final long desiredLength)
0928: throws DRDAProtocolException {
0929: return readLOBChunk(false, desiredLength);
0930: }
0931:
0932: /**
0933: * This method is used by EXTDTAReaderInputStream to read the next chunk
0934: * of data.
0935: * @param desiredLength the desired length of chunk
0936: * @exception IOException IOException
0937: */
0938: ByteArrayInputStream readLOBContinuationStream(
0939: final long desiredLength) throws IOException {
0940: try {
0941: return readLOBChunk(true, desiredLength);
0942: } catch (DRDAProtocolException e) {
0943: e.printStackTrace(agent.getServer().logWriter);
0944: throw new IOException(e.getMessage());
0945: }
0946: }
0947:
0948: /**
0949: * This method is used by EXTDTAReaderInputStream to read the next chunk
0950: * of data.
0951: * @param readHeader set to true if the dss continuation should be read
0952: * @param desiredLength the desired length of chunk
0953: * @exception DRDAProtocolException standard DRDA protocol exception
0954: */
0955: private ByteArrayInputStream readLOBChunk(final boolean readHeader,
0956: final long desiredLength) throws DRDAProtocolException {
0957: if (readHeader) {
0958: readDSSContinuationHeader();
0959: }
0960: int copySize = (int) Math.min(dssLength, desiredLength);
0961:
0962: // read the segment
0963: ensureALayerDataInBuffer(copySize);
0964: adjustLengths(copySize);
0965:
0966: // Create ByteArrayInputStream on top of buffer.
0967: // This will not make a copy of the buffer.
0968: ByteArrayInputStream bais = new ByteArrayInputStream(buffer,
0969: pos, copySize);
0970: pos += copySize;
0971:
0972: return bais;
0973: }
0974:
0975: byte[] getExtData(long desiredLength, boolean checkNullability)
0976: throws DRDAProtocolException {
0977: boolean readHeader;
0978: int copySize;
0979: ByteArrayOutputStream baos;
0980: boolean isLengthAndNullabilityUnknown = false;
0981:
0982: if (desiredLength != -1) {
0983: // allocate a stream based on a known amount of data
0984: baos = new ByteArrayOutputStream((int) desiredLength);
0985: } else {
0986: // allocate a stream to hold an unknown amount of data
0987: baos = new ByteArrayOutputStream();
0988: //isLengthAndNullabilityUnknown = true;
0989: // If we aren't given a length get the whole thing.
0990: desiredLength = MAX_EXTDTA_SIZE;
0991: }
0992:
0993: // check for a null EXTDTA value, if it is nullable and if streaming
0994: if (checkNullability)
0995: if (isEXTDTANull())
0996: return null;
0997:
0998: // set the amount to read for the first segment
0999: copySize = (int) Math.min(dssLength, desiredLength); //note: has already been adjusted for headers
1000:
1001: //if (checkNullability) // don't count the null byte we've already read
1002: //copySize--;
1003:
1004: do {
1005: // determine if a continuation header needs to be read after the data
1006: if (dssIsContinued)
1007: readHeader = true;
1008: else
1009: readHeader = false;
1010:
1011: // read the segment
1012: ensureALayerDataInBuffer(copySize);
1013: adjustLengths(copySize);
1014: baos.write(buffer, pos, copySize);
1015: pos += copySize;
1016: desiredLength -= copySize;
1017:
1018: // read the continuation header, if necessary
1019: if (readHeader)
1020: readDSSContinuationHeader();
1021:
1022: copySize = (int) Math.min(dssLength, desiredLength); //note: has already been adjusted for headers
1023:
1024: } while (readHeader == true && desiredLength > 0);
1025:
1026: return baos.toByteArray();
1027: }
1028:
1029: // reads a DSS continuation header
1030: // prereq: pos is positioned on the first byte of the two-byte header
1031: // post: dssIsContinued is set to true if the continuation bit is on, false otherwise
1032: // dssLength is set to DssConstants.MAXDSS_LEN - 2 (don't count the header for the next read)
1033: // helper method for getEXTDTAData
1034: private void readDSSContinuationHeader()
1035: throws DRDAProtocolException {
1036: ensureALayerDataInBuffer(2);
1037:
1038: dssLength = ((buffer[pos++] & 0xFF) << 8)
1039: + ((buffer[pos++] & 0xFF) << 0);
1040:
1041: if ((dssLength & 0x8000) == 0x8000) {
1042: dssLength = DssConstants.MAX_DSS_LENGTH;
1043: dssIsContinued = true;
1044: } else {
1045: dssIsContinued = false;
1046: }
1047: // it is a syntax error if the dss continuation header length
1048: // is less than or equal to two
1049: if (dssLength <= 2) {
1050: agent.throwSyntaxrm(
1051: CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2,
1052: DRDAProtocolException.NO_CODPNT_ARG);
1053: }
1054:
1055: dssLength -= 2; // avoid consuming the DSS cont header
1056: }
1057:
1058: // checks the null EXTDTA byte
1059: // returns true if null, false otherwise
1060: // helper method for getEXTDTAData
1061: private boolean isEXTDTANull() throws DRDAProtocolException {
1062: // make sure that the null byte is in the buffer
1063: ensureALayerDataInBuffer(1);
1064: adjustLengths(1);
1065:
1066: // examine the null byte
1067: byte nullByte = buffer[pos++];
1068: if (nullByte == (byte) 0x00)
1069: return false;
1070:
1071: return true;
1072: }
1073:
1074: /**
1075: * Convert a range of packed nybbles (up to 9 digits without overflow) to an int.
1076: * Note that for performance purpose, it does not do array-out-of-bound checking.
1077: * @param buffer buffer to read from
1078: * @param offset offset in the buffer
1079: * @param startNybble start nybble
1080: * @param numberOfNybbles number of nybbles
1081: * @return an int value
1082: */
1083: private int packedNybblesToInt(byte[] buffer, int offset,
1084: int startNybble, int numberOfNybbles) {
1085: int value = 0;
1086:
1087: int i = startNybble / 2;
1088: if ((startNybble % 2) != 0) {
1089: // process low nybble of the first byte if necessary.
1090: value += buffer[offset + i] & 0x0F;
1091: i++;
1092: }
1093:
1094: int endNybble = startNybble + numberOfNybbles - 1;
1095: for (; i < (endNybble + 1) / 2; i++) {
1096: value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble.
1097: value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble.
1098: }
1099:
1100: if ((endNybble % 2) == 0) {
1101: // process high nybble of the last byte if necessary.
1102: value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4);
1103: }
1104:
1105: return value;
1106: }
1107:
1108: /**
1109: * Convert a range of packed nybbles (up to 18 digits without overflow) to a long.
1110: * Note that for performance purpose, it does not do array-out-of-bound checking.
1111: * @param buffer buffer to read from
1112: * @param offset offset in the buffer
1113: * @param startNybble start nybble
1114: * @param numberOfNybbles number of nybbles
1115: * @return an long value
1116: */
1117: private long packedNybblesToLong(byte[] buffer, int offset,
1118: int startNybble, int numberOfNybbles) {
1119: long value = 0;
1120:
1121: int i = startNybble / 2;
1122: if ((startNybble % 2) != 0) {
1123: // process low nybble of the first byte if necessary.
1124: value += buffer[offset + i] & 0x0F;
1125: i++;
1126: }
1127:
1128: int endNybble = startNybble + numberOfNybbles - 1;
1129: for (; i < (endNybble + 1) / 2; i++) {
1130: value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble.
1131: value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble.
1132: }
1133:
1134: if ((endNybble % 2) == 0) {
1135: // process high nybble of the last byte if necessary.
1136: value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4);
1137: }
1138:
1139: return value;
1140: }
1141:
1142: /**
1143: * Compute the int array of magnitude from input value segments.
1144: * @param input value segments
1145: * @return array of int magnitudes
1146: */
1147: private int[] computeMagnitude(int[] input) {
1148: int length = input.length;
1149: int[] mag = new int[length];
1150:
1151: mag[length - 1] = input[length - 1];
1152: for (int i = 0; i < length - 1; i++) {
1153: int carry = 0;
1154: int j = tenRadixMagnitude[i].length - 1;
1155: int k = length - 1;
1156: for (; j >= 0; j--, k--) {
1157: long product = (input[length - 2 - i] & 0xFFFFFFFFL)
1158: * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL)
1159: + (mag[k] & 0xFFFFFFFFL) // add previous value
1160: + (carry & 0xFFFFFFFFL); // add carry
1161: carry = (int) (product >>> 32);
1162: mag[k] = (int) (product & 0xFFFFFFFFL);
1163: }
1164: mag[k] = (int) carry;
1165: }
1166: return mag;
1167: }
1168:
1169: /**
1170: * Read boolean value
1171: * @return value
1172: *
1173: * @exception DRDProtocolException
1174: */
1175: protected boolean readBoolean() throws DRDAProtocolException {
1176: ensureBLayerDataInBuffer(1, ADJUST_LENGTHS);
1177: return buffer[pos++] != 0;
1178: }
1179:
1180: /**
1181: * Read encrypted string
1182: * @param decryptM decryption manager
1183: * @param securityMechanism security mechanism
1184: * @param initVector initialization vector for cipher
1185: * @param sourcePublicKey public key (as in Deffie-Hellman algorithm)
1186: * from source (encryptor)
1187: * @return decrypted string
1188: *
1189: * @exception DRDProtocolException, SQLException(wrapping any exception in decryption)
1190: */
1191: protected String readEncryptedString(DecryptionManager decryptM,
1192: int securityMechanism, byte[] initVector,
1193: byte[] sourcePublicKey) throws DRDAProtocolException,
1194: java.sql.SQLException {
1195: byte[] cipherText = readBytes();
1196: byte[] plainText = null;
1197: plainText = decryptM.decryptData(cipherText, securityMechanism,
1198: initVector, sourcePublicKey);
1199: if (plainText == null)
1200: return null;
1201: else
1202: return ccsidManager.convertToUCS2(plainText);
1203: }
1204:
1205: /**
1206: * Read string value
1207: * Strings in DRDA protocol are encoded in EBCDIC by default so we
1208: * need to convert to UCS2
1209: * @param length - length of string to read
1210: * @return value
1211: *
1212: * @exception DRDProtocolException
1213: */
1214: protected String readString(int length)
1215: throws DRDAProtocolException {
1216: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
1217:
1218: String result = ccsidManager.convertToUCS2(buffer, pos, length);
1219: pos += length;
1220: return result;
1221: }
1222:
1223: /**
1224: * Read string value into a <code>DRDAString</code> object.
1225: *
1226: * @param dst destination for the read string
1227: * @param size size (in bytes) of string to read
1228: * @param unpad if true, remove padding (trailing spaces)
1229: *
1230: * @exception DRDAProtocolException
1231: */
1232: protected void readString(DRDAString dst, int size, boolean unpad)
1233: throws DRDAProtocolException {
1234: ensureBLayerDataInBuffer(size, ADJUST_LENGTHS);
1235: int startPos = pos;
1236: pos += size;
1237: if (unpad) {
1238: while ((size > 0)
1239: && (buffer[startPos + size - 1] == ccsidManager.space)) {
1240: --size;
1241: }
1242: }
1243: dst.setBytes(buffer, startPos, size);
1244: }
1245:
1246: /**
1247: * Read encoded string value
1248: * @param length - length of string to read
1249: * @return value
1250: *
1251: * @exception DRDProtocolException
1252: */
1253: protected String readString(int length, String encoding)
1254: throws DRDAProtocolException {
1255: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
1256: String s = null;
1257:
1258: try {
1259: s = new String(buffer, pos, length, encoding);
1260: } catch (java.io.UnsupportedEncodingException e) {
1261: agent
1262: .agentError("UnsupportedEncodingException in readString, encoding = "
1263: + encoding);
1264: e.printStackTrace(agent.getServer().logWriter);
1265: }
1266:
1267: pos += length;
1268: return s;
1269: }
1270:
1271: /**
1272: * Read string value in DDM data with default encoding
1273: * @return value
1274: *
1275: * @exception DRDProtocolException
1276: */
1277: protected String readStringData() throws DRDAProtocolException {
1278: return readString((int) ddmScalarLen,
1279: NetworkServerControlImpl.DEFAULT_ENCODING);
1280: }
1281:
1282: /**
1283: * Read specified length of string value in DDM data with default encoding
1284: * @param length - length of string to read
1285: * @return value
1286: *
1287: * @exception DRDProtocolException
1288: */
1289: protected String readStringData(int length)
1290: throws DRDAProtocolException {
1291: return readString(length,
1292: NetworkServerControlImpl.DEFAULT_ENCODING);
1293: }
1294:
1295: /**
1296: * Read length delimited string value in DDM data with default encoding
1297: * @return value
1298: *
1299: * @exception DRDProtocolException
1300: */
1301: protected String readLDStringData(String encoding)
1302: throws DRDAProtocolException {
1303: int length = readNetworkShort();
1304: return readString(length, encoding);
1305: }
1306:
1307: /**
1308: * Read string value
1309: *
1310: * @exception DRDProtocolException
1311: */
1312: protected String readString() throws DRDAProtocolException {
1313: return readString((int) ddmScalarLen);
1314: }
1315:
1316: /**
1317: * Read byte string value
1318: * @param length - length of string to read
1319: * @return byte array
1320: *
1321: * @exception DRDProtocolException
1322: */
1323: protected byte[] readBytes(int length) throws DRDAProtocolException {
1324: byte[] b;
1325:
1326: if (length < DssConstants.MAX_DSS_LENGTH) {
1327: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
1328: b = new byte[length];
1329: System.arraycopy(buffer, pos, b, 0, length);
1330: pos += length;
1331: } else
1332: b = getExtData(length, false);
1333: return b;
1334: }
1335:
1336: /**
1337: * Read byte string value
1338: * @return byte array
1339: *
1340: * @exception DRDProtocolException
1341: */
1342: protected byte[] readBytes() throws DRDAProtocolException {
1343: return readBytes((int) ddmScalarLen);
1344: }
1345:
1346: /**
1347: * Skip byte string value
1348: * @param length - length of string to skip
1349: *
1350: * @exception DRDProtocolException
1351: */
1352: protected void skipBytes(int length) throws DRDAProtocolException {
1353: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
1354: pos += length;
1355: }
1356:
1357: /**
1358: * Skip byte string value
1359: *
1360: * @exception DRDAProtocolException
1361: */
1362: protected void skipBytes() throws DRDAProtocolException {
1363: skipBytes((int) ddmScalarLen);
1364: }
1365:
1366: /**
1367: * Skip remaining DSS
1368: *
1369: * @exception DRDAProtocolException
1370: */
1371: protected void skipDss() throws DRDAProtocolException {
1372: while (dssIsContinued) {
1373: skipBytes((int) dssLength);
1374: readDSSContinuationHeader();
1375: }
1376: skipBytes((int) dssLength);
1377: topDdmCollectionStack = EMPTY_STACK;
1378: ddmScalarLen = 0;
1379: dssLength = 0;
1380:
1381: }
1382:
1383: protected void clearBuffer() throws DRDAProtocolException {
1384: skipBytes(java.lang.Math.min(dssLength, count - pos));
1385: dssIsChainedWithSameID = false;
1386: dssIsChainedWithDiffID = false;
1387: }
1388:
1389: /**
1390: * Convert EBCDIC byte array to unicode string
1391: *
1392: * @param buf - byte array
1393: * @return string
1394: */
1395: protected String convertBytes(byte[] buf) {
1396: return ccsidManager.convertToUCS2(buf, 0, buf.length);
1397: }
1398:
1399: // Private methods
1400: /**
1401: * Adjust remaining length
1402: *
1403: * @param length - adjustment length
1404: */
1405: private void adjustLengths(int length) {
1406: ddmScalarLen -= length;
1407: for (int i = 0; i <= topDdmCollectionStack; i++) {
1408: ddmCollectionLenStack[i] -= length;
1409: }
1410: dssLength -= length;
1411: }
1412:
1413: /********************************************************************/
1414: /* NetworkServerControl command protocol reading routines
1415: */
1416: /********************************************************************/
1417: /**
1418: * Read string value
1419: * @param length - length of string to read
1420: * @return value
1421: *
1422: * @exception DRDProtocolException
1423: */
1424: protected String readCmdString(int length)
1425: throws DRDAProtocolException,
1426: java.io.UnsupportedEncodingException {
1427: if (length == 0)
1428: return null;
1429:
1430: ensureBLayerDataInBuffer(length, ADJUST_LENGTHS);
1431: String result = new String(buffer, pos, length,
1432: NetworkServerControlImpl.DEFAULT_ENCODING);
1433: pos += length;
1434: return result;
1435: }
1436:
1437: /**
1438: * Read string value
1439: * @return value
1440: *
1441: * @exception DRDProtocolException
1442: */
1443: protected String readCmdString() throws DRDAProtocolException,
1444: java.io.UnsupportedEncodingException {
1445: int length = readNetworkShort();
1446: return readCmdString(length);
1447:
1448: }
1449:
1450: /**************************************************************************/
1451: /* Private methods
1452: /**************************************************************************/
1453: /**
1454: * Make sure a certain amount of Layer A data is in the buffer.
1455: * The data will be in the buffer after this method is called.
1456: *
1457: * @param desiredDataSize - amount of data we need
1458: *
1459: * @exception DRDAProtocolException
1460: */
1461: private void ensureALayerDataInBuffer(int desiredDataSize)
1462: throws DRDAProtocolException {
1463: // calulate the the number of bytes in the buffer.
1464: int avail = count - pos;
1465:
1466: // read more bytes off the network if the data is not in the buffer already.
1467: if (avail < desiredDataSize) {
1468: fill(desiredDataSize - avail);
1469: }
1470: }
1471:
1472: /**
1473: * Make sure a certain amount of Layer B data is in the buffer.
1474: * The data will be in the buffer after this method is called.
1475: *
1476: * @param desiredDataSize - amount of data we need
1477: * @param adjustLen - whether to adjust the remaining lengths
1478: *
1479: * @exception DRDProtocolException
1480: */
1481: private void ensureBLayerDataInBuffer(int desiredDataSize,
1482: boolean adjustLen) throws DRDAProtocolException {
1483: ensureALayerDataInBuffer(desiredDataSize);
1484: if (dssIsContinued) {
1485: if (desiredDataSize > dssLength) {
1486: int continueDssHeaderCount = (((desiredDataSize - dssLength) / DssConstants.MAX_DSS_LENGTH) + 1);
1487: compressBLayerData(continueDssHeaderCount);
1488: }
1489: }
1490: if (adjustLen)
1491: adjustLengths(desiredDataSize);
1492: }
1493:
1494: /**
1495: * Compress B Layer data if extended total length is used
1496: * by removing the continuation headers
1497: *
1498: * @param continueDssHeaderCount - amount of data we need
1499: *
1500: * @exception throws DRDAProtocolException
1501: */
1502: private void compressBLayerData(int continueDssHeaderCount)
1503: throws DRDAProtocolException {
1504:
1505: // jump to the last continuation header.
1506: int tempPos = 0;
1507: for (int i = 0; i < continueDssHeaderCount; i++) {
1508: // the first may be less than the size of a full DSS
1509: if (i == 0) {
1510: // only jump by the number of bytes remaining in the current DSS
1511: tempPos = pos + dssLength;
1512: } else {
1513: // all other jumps are for a full continued DSS
1514: tempPos += DssConstants.MAX_DSS_LENGTH;
1515: }
1516: }
1517:
1518: // for each of the DSS headers to remove,
1519: // read out the continuation header and increment the DSS length by the
1520: // size of the continuation bytes, then shift the continuation data as needed.
1521: int shiftSize = 0;
1522: int bytesToShift = 0;
1523: int continueHeaderLength = 0;
1524: int newdssLength = 0;
1525:
1526: for (int i = 0; i < continueDssHeaderCount; i++) {
1527: continueHeaderLength = ((buffer[tempPos] & 0xff) << 8)
1528: + ((buffer[tempPos + 1] & 0xff) << 0);
1529:
1530: if (i == 0) {
1531: // if this is the last one (farthest down stream and first to strip out)
1532:
1533: if ((continueHeaderLength & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) {
1534: // the last DSS header is again continued
1535: continueHeaderLength = DssConstants.MAX_DSS_LENGTH;
1536: dssIsContinued = true;
1537: } else {
1538: // the last DSS header was not contiued so update continue state flag
1539: dssIsContinued = false;
1540: }
1541: // the very first shift size is 2
1542: shiftSize = 2;
1543: } else {
1544: // already removed the last header so make sure the chaining flag is on
1545: if ((continueHeaderLength & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) {
1546: continueHeaderLength = DssConstants.MAX_DSS_LENGTH;
1547: } else {
1548: // this is a syntax error but not really certain which one.
1549: // for now pick 0x02 which is DSS header Length does not
1550: // match the number
1551: // of bytes of data found.
1552: agent
1553: .throwSyntaxrm(
1554: CodePoint.SYNERRCD_DSS_LENGTH_BYTE_NUMBER_MISMATCH,
1555: DRDAProtocolException.NO_CODPNT_ARG);
1556: }
1557: // increase the shift size by 2
1558: shiftSize += 2;
1559: }
1560:
1561: // it is a syntax error if the DSS continuation is less
1562: // than or equal to two
1563: if (continueHeaderLength <= 2) {
1564: agent.throwSyntaxrm(
1565: CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2,
1566: DRDAProtocolException.NO_CODPNT_ARG);
1567: }
1568:
1569: newdssLength += (continueHeaderLength - 2);
1570:
1571: // calculate the number of bytes to shift
1572: if (i != (continueDssHeaderCount - 1))
1573: bytesToShift = DssConstants.MAX_DSS_LENGTH;
1574: else
1575: bytesToShift = dssLength;
1576:
1577: tempPos -= (bytesToShift - 2);
1578: System.arraycopy(buffer, tempPos - shiftSize, buffer,
1579: tempPos, bytesToShift);
1580: }
1581: // reposition the start of the data after the final DSS shift.
1582: pos = tempPos;
1583: dssLength += newdssLength;
1584: }
1585:
1586: /**
1587: * Methods to manage the data buffer.
1588: * Methods orginally from JCC
1589: * RESOLVE: need to check if this is the best performing way of doing this
1590: */
1591:
1592: /**
1593: * This is a helper method which shifts the buffered bytes from
1594: * wherever they are in the current buffer to the beginning of
1595: * different buffer (note these buffers could be the same).
1596: * State information is updated as needed after the shift.
1597: * @param destinationBuffer - buffer to shift data to
1598: */
1599: private void shiftBuffer(byte[] destinationBuffer) {
1600: // calculate the size of the data in the current buffer.
1601: int sz = count - pos;
1602: if (SanityManager.DEBUG) {
1603: if ((sz < 0 || pos < 0)) {
1604: SanityManager
1605: .THROWASSERT("Unexpected data size or position. sz="
1606: + sz
1607: + " count="
1608: + count
1609: + " pos="
1610: + pos);
1611: }
1612: }
1613:
1614: // copy this data to the new buffer startsing at position 0.
1615: System.arraycopy(buffer, pos, destinationBuffer, 0, sz);
1616:
1617: // update the state information for data in the new buffer.
1618: pos = 0;
1619: count = sz;
1620:
1621: // replace the old buffer with the new buffer.
1622: buffer = destinationBuffer;
1623: }
1624:
1625: /**
1626: * This method makes sure there is enough room in the buffer
1627: * for a certain number of bytes. This method will allocate
1628: * a new buffer if needed and shift the bytes in the current buffer
1629: * to make ensure space is available for a fill. Right now
1630: * this method will shift bytes as needed to make sure there is
1631: * as much room as possible in the buffer before trying to
1632: * do the read. The idea is to try to have space to get as much data as possible
1633: * if we need to do a read on the socket's stream.
1634: *
1635: * @param desiredSpace - amount of data we need
1636: */
1637: private void ensureSpaceInBufferForFill(int desiredSpace) {
1638: // calculate the total unused space in the buffer.
1639: // this includes any space at the end of the buffer and any free
1640: // space at the beginning resulting from bytes already read.
1641: int currentAvailableSpace = (buffer.length - count) + pos;
1642:
1643: // check to see if there is enough free space.
1644: if (currentAvailableSpace < desiredSpace) {
1645:
1646: // there is not enough free space so we need more storage.
1647: // we are going to double the buffer unless that happens to still be
1648: // too small. If more than double the buffer is needed,
1649: // use the smallest amount over this as possible.
1650: int doubleBufferSize = (2 * buffer.length);
1651: int minumNewBufferSize = (desiredSpace - currentAvailableSpace)
1652: + buffer.length;
1653: int newsz = minumNewBufferSize <= doubleBufferSize ? doubleBufferSize
1654: : minumNewBufferSize;
1655:
1656: byte[] newBuffer = new byte[newsz];
1657:
1658: // shift everything from the old buffer to the new buffer
1659: shiftBuffer(newBuffer);
1660: } else {
1661:
1662: // there is enough free space in the buffer but let's make sure
1663: // it is all at the end.
1664: // this is also important because if we are going to do a read,
1665: // it would be nice
1666: // to get as much data as possible and making room at the end
1667: // if the buffer helps to ensure this.
1668: if (pos != 0) {
1669: shiftBuffer(buffer);
1670: }
1671: }
1672: }
1673:
1674: /**
1675: * This method will attempt to read a minimum number of bytes
1676: * from the underlying stream. This method will keep trying to
1677: * read bytes until it has obtained at least the minimum number.
1678: * @param minimumBytesNeeded - minimum required bytes
1679: *
1680: * @exception DRDProtocolException
1681: */
1682: private void fill(int minimumBytesNeeded)
1683: throws DRDAProtocolException {
1684: // make sure that there is enough space in the buffer to hold
1685: // the minimum number of bytes needed.
1686: ensureSpaceInBufferForFill(minimumBytesNeeded);
1687:
1688: // read until the minimum number of bytes needed is now in the buffer.
1689: // hopefully the read method will return as many bytes as it can.
1690: int totalBytesRead = 0;
1691: int actualBytesRead = 0;
1692: do {
1693: try {
1694: actualBytesRead = inputStream.read(buffer, count,
1695: buffer.length - count);
1696: } catch (java.io.IOException ioe) {
1697: agent.markCommunicationsFailure("DDMReader.fill()",
1698: "InputStream.read()", ioe.getMessage(), "*");
1699: } finally {
1700: if ((dssTrace != null) && dssTrace.isComBufferTraceOn())
1701: dssTrace.writeComBufferData(buffer, count,
1702: actualBytesRead,
1703: DssTrace.TYPE_TRACE_RECEIVE, "Request",
1704: "fill", 5);
1705: }
1706: if (actualBytesRead != -1) {
1707: count += actualBytesRead;
1708: totalBytesRead += actualBytesRead;
1709: }
1710:
1711: } while ((totalBytesRead < minimumBytesNeeded)
1712: && (actualBytesRead != -1));
1713: if (actualBytesRead == -1) {
1714: if (totalBytesRead < minimumBytesNeeded) {
1715: agent.markCommunicationsFailure("DDMReader.fill()",
1716: "InputStream.read()", "insufficient data", "*");
1717: }
1718: }
1719: }
1720:
1721: /**
1722: * Print a internal trace message
1723: */
1724: private void trace(String msg) {
1725: if (agent != null)
1726: agent.trace(msg);
1727: }
1728:
1729: protected String toDebugString(String indent) {
1730: String s = indent + "***** DDMReader toDebugString ******\n";
1731: int buflen = 0;
1732: if (buffer != null)
1733: buflen = buffer.length;
1734: s += indent + "Reader buffer length = " + buffer.length + "\n";
1735: return s;
1736: }
1737:
1738: /**
1739: * Return chaining bit for current DSS.
1740: */
1741: protected byte getCurrChainState() {
1742:
1743: if (!dssIsChainedWithSameID && !dssIsChainedWithDiffID)
1744: return DssConstants.DSS_NOCHAIN;
1745:
1746: if (dssIsChainedWithSameID)
1747: return DssConstants.DSSCHAIN_SAME_ID;
1748:
1749: return DssConstants.DSSCHAIN;
1750:
1751: }
1752:
1753: }
|