Package org.platformlayer.ssh.mina.bugfix

Source Code of org.platformlayer.ssh.mina.bugfix.BugFixChannelExec

package org.platformlayer.ssh.mina.bugfix;

import java.io.IOException;
import java.io.InputStream;

import org.apache.sshd.ClientSession;
import org.apache.sshd.client.channel.ChannelSession;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.util.Buffer;

public class BugFixChannelExec extends ChannelSession {
  private static final boolean USE_BUG_FIX = true;

  private final String command;

  private boolean agentForwarding;

  public BugFixChannelExec(String command) {
    if (command == null) {
      throw new IllegalArgumentException("command must not be null");
    }
    this.command = command;
  }

  @Override
  protected void sendEof() throws IOException {
    if (closeFuture.isClosed()) {
      log.warn("Blocking attempt to send SSH_MSG_CHANNEL_EOF on closed channel");
      return;
    }
    if (recipient == 0) {
      log.warn("Blocking attempt to send SSH_MSG_CHANNEL_EOF with recipient == 0");
      return;
    }
    super.sendEof();
  }

  // I hit this bug (100% CPU); it's fixed in the latest SVN.
  // TODO: Remove BugFixChannelExec when the if (len < 0) sendEof() logic is in mina-sshd.
  @Override
  protected void pumpInputStream() {
    try {
      while (!closeFuture.isClosed()) {
        Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_DATA, 0);
        buffer.putInt(recipient);
        int wpos1 = buffer.wpos(); // keep buffer position to write data length later
        buffer.putInt(0);
        int wpos2 = buffer.wpos(); // keep buffer position for data write
        buffer.wpos(wpos2 + remoteWindow.getPacketSize()); // Make room
        int len = securedRead(in, buffer.array(), wpos2, remoteWindow.getPacketSize()); // read data into buffer
        if (len > 0) {
          buffer.wpos(wpos1);
          buffer.putInt(len);
          buffer.wpos(wpos2 + len);
          remoteWindow.waitAndConsume(len);
          log.debug("Send SSH_MSG_CHANNEL_DATA on channel {}", id);
          session.writePacket(buffer);
        } else {
          // This is the bug fix we need!!
          sendEof();
          break;
        }
      }
    } catch (Exception e) {
      if (!closing) {
        log.info("Caught exception", e);
        close(false);
      }
    }
  }

  //
  // On some platforms, a call to System.in.read(new byte[65536], 0,32768) always throws an IOException.
  // So we need to protect against that and chunk the call into smaller calls.
  // This problem was found on Windows, JDK 1.6.0_03-b05.
  //
  @Override
  protected int securedRead(InputStream in, byte[] buf, int off, int len) throws IOException {
    int n = 0;
    for (;;) {
      int nread = in.read(buf, off + n, Math.min(1024, len - n));
      if (nread <= 0) {
        return (n == 0) ? nread : n;
      }
      n += nread;
      if (n >= len) {
        return n;
      }
      // if not closed but no bytes available, return
      if (in != null && in.available() <= 0) {
        return n;
      }
    }
  }

  public static ChannelSession createExecChannel(ClientSession clientSession, String command,
      boolean useAgentForwarding) throws Exception {
    if (!USE_BUG_FIX) {
      return clientSession.createExecChannel(command);
    } else {
      BugFixChannelExec channel = new BugFixChannelExec(command);

      if (useAgentForwarding) {
        channel.setAgentForwarding(true);
      }

      ((org.apache.sshd.client.session.ClientSessionImpl) clientSession).registerChannel(channel);
      return channel;
    }
  }

  @Override
  protected void doOpen() throws Exception {
    super.doOpen();

    Buffer buffer;

    if (agentForwarding) {
      log.info("Send agent forwarding request");
      buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_REQUEST, 0);
      buffer.putInt(recipient);
      buffer.putString("auth-agent-req@openssh.com");
      buffer.putBoolean(false);
      session.writePacket(buffer);
    }

    log.info("Send SSH_MSG_CHANNEL_REQUEST exec");
    buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_REQUEST, 0);
    buffer.putInt(recipient);
    buffer.putString("exec");
    buffer.putBoolean(false);
    buffer.putString(command);
    session.writePacket(buffer);

  }

  public boolean isAgentForwarding() {
    return agentForwarding;
  }

  public void setAgentForwarding(boolean agentForwarding) {
    this.agentForwarding = agentForwarding;
  }

}
TOP

Related Classes of org.platformlayer.ssh.mina.bugfix.BugFixChannelExec

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.