1

I wrote a program which just runs a command on remote machine and then halts. There is a program:

import com.jcraft.jsch.*;
import java.io.*;

public class JSchTest {
    private static String readString(String prompt) {     
        if (prompt != null) {
            System.out.println(prompt);
        }
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));  
        String input = null;
        try {
            input = in.readLine();
        } catch (IOException e) {
            System.err.println(e);
        }        
        return input;
    }

    private static boolean readBoolean(String prompt) {
        while (true) {
            String input = readString(prompt);
            if (input.equalsIgnoreCase("Y") || input.equalsIgnoreCase("N")) {
                return input.equalsIgnoreCase("Y");
            } else {
                System.out.println("Enter Y or N.");
            }
        }
    }

    public static void main(String[] args) throws Exception {  
        JSch jsch = new JSch();
        Session session = jsch.getSession(readString("Login:"),
            readString("Server:"), Integer.parseInt(readString("Port:")));
        session.setUserInfo(
            new UserInfo() {
                @Override
                public String getPassphrase() {
                    return readString("Passphrase:");
                }

                @Override
                public String getPassword() {
                    return readString("Password:");
                }

                @Override
                public boolean promptPassword(String message) {
                    return readBoolean(message);
                }

                @Override
                public boolean promptPassphrase(String message) {
                    return readBoolean(message);
                }

                @Override
                public boolean promptYesNo(String message) {
                    return readBoolean(message);
                }

                @Override
                public void showMessage(String message) {
                    System.out.println(message);
                }
            }
        );
        session.connect();
        ChannelExec channel = (ChannelExec)session.openChannel("exec");
        InputStream in = channel.getInputStream();
        channel.setCommand(readString("Command:"));
        channel.connect();         
        byte[] buffer = new byte[1024]; 
        int bytes;
        do {
            while (in.available() > 0) {
                bytes = in.read(buffer, 0, 1024);
                System.out.print(new String(buffer, 0, bytes));
            }
        } while (!channel.isClosed());                        
        channel.disconnect();
        session.disconnect();            
    }    
}

This program works fine when I'm using commands which produce output only, such as echo Hello. But when I'm trying to pass in a command such as read VAR;echo You entered: $VAR my program is running into infinite loop, because channel isn't closed and is waiting for an input.

Ok, so I got channel's output stream to write an input for

        OutputStream out = channel.getOutputStream();

and made i/o loop looking like this:

        while (true) {
            while (in.available() > 0) {
                bytes = in.read(buffer, 0, 1024);
                System.out.print(new String(buffer, 0, bytes));
            }
            if (channel.isClosed()) {
                break;
            } else if (true /* channel.isWaitingForInput() */) {
                String output = readString(null) + "\n";
                out.write(output.getBytes());
                out.flush();
            }
        }

But as you can see - I have no information about what is happening on the channel's other side. Is there is an input which I must provide now, or not? So my program is asking for an input anytime, though even is not needed.

So there is a question - how can I know when I must pass in an input for a channel, or, maybe, how can I rewrite my program so it won't just only running a commands, but also providing an input for them, when needed (but halting at the end anyway)?

Viktor
  • 1,298
  • 15
  • 28
  • Check out my response to this question http://stackoverflow.com/questions/16298279/never-ending-of-reading-server-response-using-jsch/16319567#16319567 – Damienknight May 07 '13 at 17:39

1 Answers1

1

The channel stays open until it is disconnected. It does not even disconnect automatically when you send the exit command and are logged off the host.

You need to check for channel.getExitStatus > -1. The exit status is -1 until the session is closed by host (usually triggered by the user typing 'exit').

Once the exit status has returned other than -1, you can optionally process the exit status (ie, was it a clean exit, or were there error). You need to disconnect the channel yourself after that:

  Channel channel=session.openChannel("shell");

  channel.setInputStream(System.in);
  channel.setOutputStream(System.out);

  channel.connect();

  while (channel.getExitStatus() == -1){
     try{Thread.sleep(1000);}catch(Exception e){System.out.println(e);}
  }

  channel.disconnect();

With the loop above, any standard input into the java console will be sent to the channel, and once the user sends 'exit', the channel disconnects.

There is a working example here: Never ending of reading server response using jSch

Also, the jcraft example (which does not actually close when you 'exit', but is an otherwise working example). http://www.jcraft.com/jsch/examples/UserAuthKI.java

Community
  • 1
  • 1
Damienknight
  • 1,876
  • 2
  • 18
  • 34