private void processHandshake() throws IOException {
    boolean read;
    do {
      read = false;
      /*
       * We need the first 4 bytes, they contain type and length of the message.
       */
      if (handshakeQueue.size() >= 4) {
        byte[] beginning = new byte[4];
        handshakeQueue.read(beginning, 0, 4, 0);
        ByteArrayInputStream bis = new ByteArrayInputStream(beginning);
        short type = TlsUtils.readUint8(bis);
        int len = TlsUtils.readUint24(bis);

        /*
         * Check if we have enough bytes in the buffer to read the full message.
         */
        if (handshakeQueue.size() >= (len + 4)) {
          /*
           * Read the message.
           */
          byte[] buf = new byte[len];
          handshakeQueue.read(buf, 0, len, 4);
          handshakeQueue.removeData(len + 4);

          /*
           * RFC 2246 7.4.9. The value handshake_messages includes all handshake
           * messages starting at client hello up to, but not including, this
           * finished message. [..] Note: [Also,] Hello Request messages are
           * omitted from handshake hashes.
           */
          switch (type) {
            case HandshakeType.hello_request:
            case HandshakeType.finished:
              break;
            default:
              rs.updateHandshakeData(beginning, 0, 4);
              rs.updateHandshakeData(buf, 0, len);
              break;
          }

          /*
           * Now, parse the message.
           */
          processHandshakeMessage(type, buf);
          read = true;
        }
      }
    } while (read);
  }
  /**
   * Read data from the network. The method will return immediately, if there is still some data
   * left in the buffer, or block until some application data has been read from the network.
   *
   * @param buf The buffer where the data will be copied to.
   * @param offset The position where the data will be placed in the buffer.
   * @param len The maximum number of bytes to read.
   * @return The number of bytes read.
   * @throws IOException If something goes wrong during reading data.
   */
  protected int readApplicationData(byte[] buf, int offset, int len) throws IOException {
    while (applicationDataQueue.size() == 0) {
      /*
       * We need to read some data.
       */
      if (this.closed) {
        if (this.failedWithError) {
          /*
           * Something went terribly wrong, we should throw an IOException
           */
          throw new IOException(TLS_ERROR_MESSAGE);
        }

        /*
         * Connection has been closed, there is no more data to read.
         */
        return -1;
      }

      safeReadData();
    }
    len = Math.min(len, applicationDataQueue.size());
    applicationDataQueue.read(buf, offset, len, 0);
    applicationDataQueue.removeData(len);
    return len;
  }
  /**
   * This method is called, when a change cipher spec message is received.
   *
   * @throws IOException If the message has an invalid content or the handshake is not in the
   *     correct state.
   */
  private void processChangeCipherSpec() throws IOException {
    while (changeCipherSpecQueue.size() > 0) {
      /*
       * A change cipher spec message is only one byte with the value 1.
       */
      byte[] b = new byte[1];
      changeCipherSpecQueue.read(b, 0, 1, 0);
      changeCipherSpecQueue.removeData(1);
      if (b[0] != 1) {
        /*
         * This should never happen.
         */
        this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
      }

      /*
       * Check if we are in the correct connection state.
       */
      if (this.connection_state != CS_CLIENT_FINISHED_SEND) {
        this.failWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
      }

      rs.serverClientSpecReceived();

      this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
    }
  }
  /** Look for new input from the ptty, send it to the terminal emulator. */
  private void readFromProcess() {
    int bytesAvailable = mByteQueue.getBytesAvailable();
    int bytesToRead = Math.min(bytesAvailable, mReceiveBuffer.length);
    int bytesRead = 0;
    try {
      bytesRead = mByteQueue.read(mReceiveBuffer, 0, bytesToRead);
    } catch (InterruptedException e) {
      return;
    }

    // Give subclasses a chance to process the read data
    processInput(mReceiveBuffer, 0, bytesRead);
    notifyUpdate();
  }
  private void processAlert() throws IOException {
    while (alertQueue.size() >= 2) {
      /*
       * An alert is always 2 bytes. Read the alert.
       */
      byte[] tmp = new byte[2];
      alertQueue.read(tmp, 0, 2, 0);
      alertQueue.removeData(2);
      short level = tmp[0];
      short description = tmp[1];
      if (level == AlertLevel.fatal) {
        /*
         * This is a fatal error.
         */
        this.failedWithError = true;
        this.closed = true;
        /*
         * Now try to close the stream, ignore errors.
         */
        try {
          rs.close();
        } catch (Exception e) {

        }
        throw new IOException(TLS_ERROR_MESSAGE);
      } else {
        /*
         * This is just a warning.
         */
        if (description == AlertDescription.close_notify) {
          /*
           * Close notify
           */
          this.failWithError(AlertLevel.warning, AlertDescription.close_notify);
        }
        /*
         * If it is just a warning, we continue.
         */
      }
    }
  }