FileDocCategorySizeDatePackage
HandshakeIODataStream.javaAPI DocAndroid 1.5 API15399Wed May 06 22:41:06 BST 2009org.apache.harmony.xnet.provider.jsse

HandshakeIODataStream

public class HandshakeIODataStream extends org.apache.harmony.xnet.provider.jsse.SSLInputStream implements DataStream, org.apache.harmony.xnet.provider.jsse.Appendable
This class provides Input/Output data functionality for handshake layer. It provides read and write operations and accumulates all sent/received handshake's data. This class can be presented as a combination of 2 data pipes. The first data pipe is a pipe of income data: append method places the data at the beginning of the pipe, and read methods consume the data from the pipe. The second pipe is an outcoming data pipe: write operations plases the data into the pipe, and getData methods consume the data. It is important to note that work with pipe cound not be started if there is unconsumed data in another pipe. It is reasoned by the following: handshake protocol performs read and write operations consecuently. I.e. it first reads all income data and only than produces the responce and places it into the stream. The read operations of the stream presented by the methods of SSLInputStream which in its turn is an extension of InputStream. So this stream can be used as an InputStream parameter for certificate generation. Also input stream functionality supports marks. The marks help to reset the position of the stream in case of incompleate handshake records. Note that in case of exhausting of income data the EndOfBufferException is thown which implies the following: 1. the stream contains scrappy handshake record, 2. the read position should be reseted to marked, 3. and more income data is expected. The throwing of the exception (instead of returning of -1 value or incompleate filling of destination buffer) helps to speed up the process of scrappy data recognition and processing. For more information about TLS handshake process see TLS v 1 specification at http://www.ietf.org/rfc/rfc2246.txt.

Fields Summary
private static final MessageDigest
md5
private static final MessageDigest
sha
private int
buff_size
private int
inc_buff_size
private byte[]
buffer
private int
read_pos
private int
marked_pos
private int
read_pos_end
private int
write_pos
private int
write_pos_beg
Constructors Summary
public HandshakeIODataStream()

        try {
            md5 = MessageDigest.getInstance("MD5");
            sha = MessageDigest.getInstance("SHA-1");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(
                    "Could not initialize the Digest Algorithms.");
        }
    
Methods Summary
public voidappend(byte[] src)
Appends the income data to be read by handshake protocol. The attempts to overflow the buffer by meens of this methos seem to be futile because of: 1. The SSL protocol specifies the maximum size of the record and record protocol does not pass huge messages. (see TLS v1 specification http://www.ietf.org/rfc/rfc2246.txt , p 6.2) 2. After each call of this method, handshake protocol should start (and starts) the operations on received data and recognize the fake data if such was provided (to check the size of certificate for example).

        append(src, 0, src.length);
    
private voidappend(byte[] src, int from, int length)

        if (read_pos == read_pos_end) {
            // start reading state after writing
            if (write_pos_beg != write_pos) {
                // error: outboud handshake data was not sent,
                // but inbound handshake data has been received.
                throw new AlertException(
                    AlertProtocol.UNEXPECTED_MESSAGE,
                    new SSLHandshakeException(
                        "Handshake message has been received before "
                        + "the last oubound message had been sent."));
            }
            if (read_pos < write_pos) {
                read_pos = write_pos;
                read_pos_end = read_pos;
            }
        }
        if (read_pos_end + length > buff_size) {
            enlargeBuffer(read_pos_end+length-buff_size);
        }
        System.arraycopy(src, from, buffer, read_pos_end, length);
        read_pos_end += length;
    
public intavailable()


       
        return read_pos_end - read_pos;
    
private voidcheck(int length)

        // (write_pos == write_pos_beg) iff:
        // 1. there were not write operations yet
        // 2. all written data was demanded by getData methods
        if (write_pos == write_pos_beg) {
            // just started to write after the reading
            if (read_pos != read_pos_end) {
                // error: attempt to write outbound data into the stream before
                // all the inbound handshake data had been read
                throw new AlertException(
                        AlertProtocol.INTERNAL_ERROR,
                        new SSLHandshakeException("Data was not fully read: "
                        + read_pos + " " + read_pos_end));
            }
            // set up the write positions
            if (write_pos_beg < read_pos_end) {
                write_pos_beg = read_pos_end;
                write_pos = write_pos_beg;
            }
        }
        // if there is not enought free space in the buffer - enlarge it:
        if (write_pos + length >= buff_size) {
            enlargeBuffer(length);
        }
    
protected voidclearBuffer()

        read_pos = 0;
        marked_pos = 0;
        read_pos_end = 0;
        write_pos = 0;
        write_pos_beg = 0;
        Arrays.fill(buffer, (byte) 0);
    
private voidenlargeBuffer(int size)

        buff_size = (size < inc_buff_size)
            ? buff_size + inc_buff_size
            : buff_size + size;
        byte[] new_buff = new byte[buff_size];
        System.arraycopy(buffer, 0, new_buff, 0, buffer.length);
        buffer = new_buff;
    
public byte[]getData(int length)
returns the chunk of stored data with the length no more than specified.

param
length: int
return

        byte[] res;
        if (write_pos - write_pos_beg < length) {
            res = new byte[write_pos - write_pos_beg];
            System.arraycopy(buffer, write_pos_beg,
                    res, 0, write_pos-write_pos_beg);
            write_pos_beg = write_pos;
        } else {
            res = new byte[length];
            System.arraycopy(buffer, write_pos_beg, res, 0, length);
            write_pos_beg += length;
        }
        return res;
    
protected byte[]getDigestMD5()
Returns the MD5 digest of the data passed throught the stream

return
MD5 digest

        synchronized (md5) {
            int len = (read_pos_end > write_pos)
                ? read_pos_end
                : write_pos;
            md5.update(buffer, 0, len);
            return md5.digest();
        }
    
protected byte[]getDigestMD5withoutLast()
Returns the MD5 digest of the data passed throught the stream except last message

return
MD5 digest

        synchronized (md5) {
            md5.update(buffer, 0, marked_pos);
            return md5.digest();
        }
    
protected byte[]getDigestSHA()
Returns the SHA-1 digest of the data passed throught the stream

return
SHA-1 digest

        synchronized (sha) {
            int len = (read_pos_end > write_pos)
                ? read_pos_end
                : write_pos;
            sha.update(buffer, 0, len);
            return sha.digest();
        }
    
protected byte[]getDigestSHAwithoutLast()
Returns the SHA-1 digest of the data passed throught the stream except last message

return
SHA-1 digest

        synchronized (sha) {
            sha.update(buffer, 0, marked_pos);
            return sha.digest();
        }
    
protected byte[]getMessages()
Returns all the data passed throught the stream

return
all the data passed throught the stream at the moment

        int len = (read_pos_end > write_pos) ? read_pos_end : write_pos;
        byte[] res = new byte[len];
        System.arraycopy(buffer, 0, res, 0, len);
        return res;
    
public booleanhasData()

        return (write_pos > write_pos_beg);
    
public voidmark(int limit)

        marked_pos = read_pos;
    
public voidmark()

        marked_pos = read_pos;
    
public booleanmarkSupported()

        return true;
    
protected voidprintContent(java.io.PrintStream outstream)

        int perLine = 20;
        String prefix = " ";
        String delimiter = "";

        for (int i=write_pos_beg; i<write_pos; i++) {
            String tail = Integer.toHexString(
                    0x00ff & buffer[i]).toUpperCase();
            if (tail.length() == 1) {
                tail = "0" + tail;
            }
            outstream.print(prefix + tail + delimiter);

            if (((i-write_pos_beg+1)%10) == 0) {
                outstream.print(" ");
            }

            if (((i-write_pos_beg+1)%perLine) == 0) {
                outstream.println();
            }
        }
        outstream.println();
    
public intread(byte[] dest, int offset, int length)

        if (length > available()) {
            throw new EndOfBufferException();
        }
        System.arraycopy(buffer, read_pos, dest, offset, length);
        read_pos = read_pos + length;
        return length;
    
public intread()
read an opaque value;

param
byte: byte
return

        if (read_pos == read_pos_end) {
            //return -1;
            throw new EndOfBufferException();
        }
        return buffer[read_pos++] & 0xFF;
    
public byte[]read(int length)
reads vector of opaque values

param
new: long
return

        if (length > available()) {
            throw new EndOfBufferException();
        }
        byte[] res = new byte[length];
        System.arraycopy(buffer, read_pos, res, 0, length);
        read_pos = read_pos + length;
        return res;
    
protected voidremoveFromMarkedPosition()
Removes the data from the marked position to the current read position. The method is usefull when it is needed to delete one message from the internal buffer.

        System.arraycopy(buffer, read_pos, 
                buffer, marked_pos, read_pos_end - read_pos);
        read_pos_end -= (read_pos - marked_pos);
        read_pos = marked_pos;
    
public voidreset()

        read_pos = marked_pos;
    
public voidwrite(byte b)
Writes an opaque value

param
byte: byte

        check(1);
        buffer[write_pos++] = b;
    
public voidwrite(byte[] vector)
writes vector of opaque values

param
vector the vector to be written

        check(vector.length);
        System.arraycopy(vector, 0, buffer, write_pos, vector.length);
        write_pos += vector.length;
    
public voidwriteUint16(long n)
Writes Uint16 value

param
long: the value to be written (last 2 bytes)

        check(2);
        buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8);
        buffer[write_pos++] = (byte) (n & 0x00ff);
    
public voidwriteUint24(long n)
Writes Uint24 value

param
long: the value to be written (last 3 bytes)

        check(3);
        buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16);
        buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8);
        buffer[write_pos++] = (byte) (n & 0x00ff);
    
public voidwriteUint32(long n)
Writes Uint32 value

param
long: the value to be written (last 4 bytes)

        check(4);
        buffer[write_pos++] = (byte) ((n & 0x00ff000000) >> 24);
        buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16);
        buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8);
        buffer[write_pos++] = (byte) (n & 0x00ff);
    
public voidwriteUint64(long n)
Writes Uint64 value

param
long: the value to be written

        check(8);
        buffer[write_pos++] = (byte) ((n & 0x00ff00000000000000L) >> 56);
        buffer[write_pos++] = (byte) ((n & 0x00ff000000000000L) >> 48);
        buffer[write_pos++] = (byte) ((n & 0x00ff0000000000L) >> 40);
        buffer[write_pos++] = (byte) ((n & 0x00ff00000000L) >> 32);
        buffer[write_pos++] = (byte) ((n & 0x00ff000000) >> 24);
        buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16);
        buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8);
        buffer[write_pos++] = (byte) (n & 0x00ff);
    
public voidwriteUint8(long n)
Writes Uint8 value

param
long: the value to be written (last byte)

        check(1);
        buffer[write_pos++] = (byte) (n & 0x00ff);