/**
   * @param msg
   * @param sender
   * @throws IOException
   * @throws TransportProtocolException
   */
  public synchronized void sendMessage(SshMessage msg, Object sender) throws IOException {
    // Send a message, if were in key exchange then add it to
    // the list unless of course it is a transport protocol or key
    // exchange message
    if (log.isDebugEnabled()) {
      log.info("Sending " + msg.getMessageName());
    }

    int currentState = state.getValue();

    if (sender instanceof SshKeyExchange
        || sender instanceof TransportProtocolCommon
        || (currentState == TransportProtocolState.CONNECTED)) {
      sshOut.sendMessage(msg);

      if (currentState == TransportProtocolState.CONNECTED) {
        if (sendIgnore) {
          byte[] count = new byte[1];
          ConfigurationLoader.getRND().nextBytes(count);

          byte[] rand = new byte[(count[0] & 0xFF) + 1];
          ConfigurationLoader.getRND().nextBytes(rand);

          SshMsgIgnore ignore = new SshMsgIgnore(new String(rand));

          if (log.isDebugEnabled()) {
            log.debug("Sending " + ignore.getMessageName());
          }

          sshOut.sendMessage(ignore);
        }
      }
    } else if (currentState == TransportProtocolState.PERFORMING_KEYEXCHANGE) {
      log.debug("Adding to message queue whilst in key exchange");

      synchronized (messageStack) {
        // Add this message to the end of the list
        messageStack.add(msg);
      }
    } else {
      throw new TransportProtocolException("The transport protocol is disconnected");
    }
  }
 /*public InetSocketAddress getRemoteAddress() {
   return (InetSocketAddress)socket.getRemoteSocketAddress();
 }*/
 public long getOutgoingByteCount() {
   return sshOut.getNumBytesTransfered();
 }
  /**
   * @return
   * @throws IOException
   */
  protected SshMessage processMessages() throws IOException {
    byte[] msgdata = null;
    SshMessage msg;
    SshMessageStore ms;

    while (state.getValue() != TransportProtocolState.DISCONNECTED) {
      long currentTime = System.currentTimeMillis();

      transferredKB = sshIn.getNumBytesTransfered() / 1024 + sshOut.getNumBytesTransfered() / 1024;

      long kbLimit = transferredKB - lastTriggeredKB;

      if (((currentTime - startTime) > kexTimeout) || (kbLimit > kexTransferLimitKB)) {
        //    ((sshIn.getNumBytesTransfered() +
        //    sshOut.getNumBytesTransfered()) > kexTransferLimit)) {
        startTime = currentTime;
        lastTriggeredKB = transferredKB;
        if (log.isDebugEnabled()) {
          log.info("rekey");
        }
        sendKeyExchangeInit();
      }

      boolean hasmsg = false;

      while (!hasmsg) {
        try {
          msgdata = sshIn.readMessage();
          hasmsg = true;
        } catch (InterruptedIOException ex /*SocketTimeoutException ex*/) {
          log.info("Possible timeout on transport inputstream");

          Iterator it = eventHandlers.iterator();
          TransportProtocolEventHandler eventHandler;

          while (it.hasNext()) {
            eventHandler = (TransportProtocolEventHandler) it.next();
            eventHandler.onSocketTimeout(this /*,
                        provider.isConnected()*/);
          }
        }
      }

      Integer messageId = SshMessage.getMessageId(msgdata);

      if (!messageStore.isRegisteredMessage(messageId)) {
        try {
          ms = getMessageStore(messageId);
          msg = ms.createMessage(msgdata);

          if (log.isDebugEnabled()) {
            log.info("Received " + msg.getMessageName());
          }

          ms.addMessage(msg);
        } catch (MessageNotRegisteredException mnre) {
          log.info("Unimplemented message received " + String.valueOf(messageId.intValue()));
          msg = new SshMsgUnimplemented(sshIn.getSequenceNo());
          sendMessage(msg, this);
        }
      } else {
        return messageStore.createMessage(msgdata);
      }
    }

    throw new IOException("The transport protocol has disconnected");
  }