/**
   * 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;
  }
 protected void processData(short protocol, byte[] buf, int offset, int len) throws IOException {
   /*
    * Have a look at the protocol type, and add it to the correct queue.
    */
   switch (protocol) {
     case ContentType.change_cipher_spec:
       changeCipherSpecQueue.addData(buf, offset, len);
       processChangeCipherSpec();
       break;
     case ContentType.alert:
       alertQueue.addData(buf, offset, len);
       processAlert();
       break;
     case ContentType.handshake:
       handshakeQueue.addData(buf, offset, len);
       processHandshake();
       break;
     case ContentType.application_data:
       if (!appDataReady) {
         this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
       }
       applicationDataQueue.addData(buf, offset, len);
       processApplicationData();
       break;
     default:
       /*
        * Uh, we don't know this protocol.
        *
        * RFC2246 defines on page 13, that we should ignore this.
        */
   }
 }
  /**
   * 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;
    }
  }
Example #4
0
 public void testMultipleWords() {
   String[] words = new String[5];
   for (int i = 0; i < words.length; i++) {
     words[i] = "Word " + i;
   }
   OutputStream output = byteQueue.getByteOutputStream();
   String[] processedWords = new String[words.length];
   try {
     OutputStreamWriter writer = new OutputStreamWriter(output);
     for (String w : words) {
       writer.write(w);
       writer.write("\n");
     }
     writer.close();
     BufferedReader reader =
         new BufferedReader(new InputStreamReader(byteQueue.getByteInputStream()));
     String line = null;
     int index = 0;
     while ((line = reader.readLine()) != null) {
       processedWords[index++] = line;
     }
   } catch (Exception ex) {
     ex.printStackTrace();
     fail("Error pushing bytes around: " + ex.getMessage());
   }
   for (int i = 0; i < words.length; i++) {
     String original = words[i];
     String processed = processedWords[i];
     assertEquals("Word was different after pushed through queue!", original, processed);
   }
 }
Example #5
0
  public int read() throws IOException {
    if (byteq.count() == 0) {
      fillBuffer();
      if (byteq.count() == 0) {
        return -1;
      }
    }

    byte val = byteq.dequeue();
    if (val >= 0) return val;
    else return val & 0xFF;
  }
  /** 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 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);
  }
Example #8
0
 public void testHugeWord() {
   String word = generateRandomWord(8192);
   String processedWord = null;
   OutputStream output = byteQueue.getByteOutputStream();
   try {
     OutputStreamWriter writer = new OutputStreamWriter(output);
     writer.write(word);
     writer.close();
     BufferedReader reader =
         new BufferedReader(new InputStreamReader(byteQueue.getByteInputStream()));
     processedWord = reader.readLine();
   } catch (IOException ex) {
     ex.printStackTrace();
     fail("Error pushing bytes around: " + ex.getMessage());
   }
   assertEquals("Word was different after pushed through queue!", word, processedWord);
 }
 /**
  * Add some data to our buffer.
  *
  * @param data A byte-array to read data from.
  * @param offset How many bytes to skip at the beginning of the array.
  * @param len How many bytes to read from the array.
  */
 public void addData(byte[] data, int offset, int len) {
   if ((skipped + available + len) > databuf.length) {
     byte[] tmp = new byte[ByteQueue.nextTwoPow(data.length)];
     System.arraycopy(databuf, skipped, tmp, 0, available);
     skipped = 0;
     databuf = tmp;
   }
   System.arraycopy(data, offset, databuf, skipped + available, len);
   available += len;
 }
 /**
  * Write data to the terminal output. The written data will be consumed by the emulation client as
  * input.
  *
  * <p><code>write</code> itself runs on the main thread. The default implementation writes the
  * data into a circular buffer and signals the writer thread to copy it from there to the {@link
  * OutputStream}.
  *
  * <p>Subclasses may override this method to modify the output before writing it to the stream,
  * but implementations in derived classes should call through to this method to do the actual
  * writing.
  *
  * @param data An array of bytes to write to the terminal.
  * @param offset The offset into the array at which the data starts.
  * @param count The number of bytes to be written.
  */
 public void write(byte[] data, int offset, int count) {
   try {
     while (count > 0) {
       int written = mWriteQueue.write(data, offset, count);
       offset += written;
       count -= written;
       notifyNewOutput();
     }
   } catch (InterruptedException e) {
   }
 }
Example #11
0
  private void decodeAndEnqueue(byte[] data, int len) {
    int accum = 0;
    accum |= data[0] << 18;
    accum |= data[1] << 12;
    accum |= data[2] << 6;
    accum |= data[3];

    byte b1 = (byte) (accum >>> 16);
    byteq.enqueue(b1);

    if (len > 2) {
      byte b2 = (byte) ((accum >>> 8) & 0xFF);
      byteq.enqueue(b2);

      if (len > 3) {
        byte b3 = (byte) (accum & 0xFF);
        byteq.enqueue(b3);
      }
    }
  }
  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.
         */
      }
    }
  }
Example #13
0
 public void testHugeWordRetrievedInPieces() {
   String word = generateRandomWord(8192);
   String processedWord = null;
   OutputStream output = byteQueue.getByteOutputStream();
   try {
     OutputStreamWriter writer = new OutputStreamWriter(output);
     writer.write(word);
     writer.close();
     InputStreamReader reader = new InputStreamReader(byteQueue.getByteInputStream());
     StringBuffer processed = new StringBuffer();
     Random rand = new Random(System.currentTimeMillis());
     char[] charBuff = new char[rand.nextInt(32) + 16];
     int charsRead = -1;
     while ((charsRead = reader.read(charBuff)) != -1) {
       processed.append(new String(charBuff, 0, charsRead));
       charBuff = new char[rand.nextInt(32) + 16];
     }
     processedWord = processed.toString();
   } catch (IOException ex) {
     ex.printStackTrace();
     fail("Error pushing bytes around: " + ex.getMessage());
   }
   assertEquals("Word was different after pushed through queue!", word, processedWord);
 }
Example #14
0
 public void testConcurrentReadWrite() {
   // generate a bunch of garbage to test
   final List<String> originalWords = new ArrayList<String>();
   for (int i = 0; i < 4; i++) {
     // originalWords.add(generateRandomWord(8192));
     originalWords.add("Word " + i);
   }
   // writer and re-reader
   final OutputStream output = byteQueue.getByteOutputStream();
   final InputStream input = byteQueue.getByteInputStream();
   // write words in to the buffer every 1000ms
   Runnable writeRunner =
       new Runnable() {
         public void run() {
           OutputStreamWriter writer = new OutputStreamWriter(output);
           Iterator<String> wordIter = originalWords.iterator();
           while (wordIter.hasNext()) {
             try {
               writer.write(wordIter.next());
               writer.write('\n');
               Thread.sleep(1000);
             } catch (Exception ex) {
               ex.printStackTrace();
             }
           }
           try {
             writer.close();
           } catch (Exception ex) {
             ex.printStackTrace();
           }
         }
       };
   final List<String> processedWords = new ArrayList<String>();
   // read bytes out as fast as possible
   Runnable readRunner =
       new Runnable() {
         public void run() {
           BufferedReader reader = new BufferedReader(new InputStreamReader(input));
           String line = null;
           try {
             while ((line = reader.readLine()) != null) {
               processedWords.add(line);
             }
           } catch (Exception ex) {
             ex.printStackTrace();
           }
         }
       };
   // start up the processes
   Thread writeThread = new Thread(writeRunner);
   Thread readThread = new Thread(readRunner);
   writeThread.start();
   readThread.start();
   try {
     writeThread.join();
     readThread.join();
   } catch (Exception ex) {
     ex.printStackTrace();
     fail("Error waiting for worker threads: " + ex.getMessage());
   }
   assertEquals(
       "Count of words after processing was not as expected",
       originalWords.size(),
       processedWords.size());
   for (int i = 0; i < originalWords.size(); i++) {
     String original = originalWords.get(i);
     String processed = processedWords.get(i);
     assertEquals("Processed word was different from original", original, processed);
   }
 }