@Override
 public synchronized void write(int b) throws IOException {
   checkOpen();
   if (currentOutputCell == null || currentOutputCell.cellBytesRemaining() == 0)
     flushCurrentOutputCell();
   currentOutputCell.putByte(b);
 }
 public RelayCell receiveRelayResponse(int expectedCommand, Router extendTarget) {
   final RelayCell cell = circuit.receiveRelayCell();
   if (cell == null) {
     throw new TorException("Timeout building circuit");
   }
   final int command = cell.getRelayCommand();
   if (command == RelayCell.RELAY_TRUNCATED) {
     final int code = cell.getByte() & 0xFF;
     final String msg = CellImpl.errorToDescription(code);
     final String source = nodeToName(cell.getCircuitNode());
     if (code == Cell.ERROR_PROTOCOL) {
       logProtocolViolation(source, extendTarget);
     }
     throw new TorException(
         "Error from ("
             + source
             + ") while extending to ("
             + extendTarget.getNickname()
             + "): "
             + msg);
   } else if (command != expectedCommand) {
     final String expected = RelayCellImpl.commandToDescription(expectedCommand);
     final String received = RelayCellImpl.commandToDescription(command);
     throw new TorException(
         "Received incorrect extend response, expecting "
             + expected
             + " but received "
             + received);
   } else {
     return cell;
   }
 }
  private void flushCurrentOutputCell() {
    if (currentOutputCell != null
        && currentOutputCell.cellBytesConsumed() > RelayCell.HEADER_SIZE) {
      stream.waitForSendWindowAndDecrement();
      stream.getCircuit().sendRelayCell(currentOutputCell);
      bytesSent += (currentOutputCell.cellBytesConsumed() - RelayCell.HEADER_SIZE);
    }

    currentOutputCell =
        new RelayCellImpl(
            stream.getTargetNode(),
            stream.getCircuit().getCircuitId(),
            stream.getStreamId(),
            RelayCell.RELAY_DATA);
  }
  public synchronized void write(byte[] data, int offset, int length) throws IOException {
    checkOpen();
    if (currentOutputCell == null || currentOutputCell.cellBytesRemaining() == 0)
      flushCurrentOutputCell();

    while (length > 0) {
      if (length < currentOutputCell.cellBytesRemaining()) {
        currentOutputCell.putByteArray(data, offset, length);
        return;
      }
      final int writeCount = currentOutputCell.cellBytesRemaining();
      currentOutputCell.putByteArray(data, offset, writeCount);
      flushCurrentOutputCell();
      offset += writeCount;
      length -= writeCount;
    }
  }