I can connect to the router with java via jsch library and I can't get some Mikrotik command line (tool torch ether1 src-address=0.0.0.0/0 , /interface monitor-traffic ether1 ) output
public static void listFolderStructure(String username, String password,
String host, int port, String command) throws Exception {
Session session = null;
ChannelExec channel = null;
try {
session = new JSch().getSession(username, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
channel.setOutputStream(responseStream);
channel.connect();
while (channel.isConnected()) {
Thread.sleep(100);
}
String responseString = new String(responseStream.toByteArray());
System.out.println(responseString);
} finally {
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
}
Beating my head against a wall here.
I am trying in the constructor to establish a link and log on. Then in the begin method to execute a java application on the remote computer. Finally in terminate, to kill the java process.
No exceptions show up, the command just doesn't execute. I can see the user has logged in if I go to the remote terminal and run a last. The user has only a login time of 0 though. I can also get an error if I change the password to the wrong password.
But the remote java app isn't running. Remote app runs fine when I log in directly from that terminal or ssh in and run it from the command line.
Ideas? Thanks in advance.
//Constants for the login information
String HOST="<HOSTNAME>";
String USER="<userid>";
String PASSWORD="<password>";
//Constants for command strings
String START_COMMAND="java -Djava.library.path=/usr/local/share/OpenCV/java -jar <filename>";
String TERMINATE_COMMAND="killall java";
Channel channel;
Session session;
InputStream in;
public VisionProcessing(){
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
try {
System.out.println("Trying login");
session = jsch.getSession(USER, HOST, 22);
session.setPassword(PASSWORD);
session.setConfig(config); //XXX No idea what this does
session.connect();
channel=session.openChannel("exec");
((ChannelExec)channel).setPty(true);
channel.connect();//This is important
if (channel.isConnected()){
System.out.println("Connected");
} else {
System.out.println("Not Connected");
}
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Exception logging in");
}
}
public boolean beginTargeting() {
try {
StringBuilder outputBuffer = new StringBuilder();
Channel channel = session.openChannel("exec");
InputStream commandOutput = channel.getInputStream();
int readByte = commandOutput.read();
while(readByte != 0xffffffff)
{
outputBuffer.append((char)readByte);
readByte = commandOutput.read();
}
System.out.println("Begin");
if (channel.isConnected()){
System.out.println("Connected");
((ChannelExec)channel).setCommand(START_COMMAND);
} else {
System.out.println("Not Connected");
}
channel.connect();//This is important
channel.disconnect();
}catch(IOException ioX)
{
System.out.println(ioX);
}
catch(JSchException jschX)
{
System.out.println(jschX);
}
return true;
}
public boolean terminateTargeting() {
try {
System.out.println("Terminate");
channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(TERMINATE_COMMAND);
channel.connect();//This is important
System.out.println("Terminating");
channel.setInputStream(null);
channel.disconnect();
session.disconnect();
System.out.println("DONE");
}catch(Exception ee){
System.out.println(ee);
}
return true;
}
I am trying to execute a command on a Linux server using SSH from Android with JSch.
As far as I know I am connecting to the server, but when I attempt to retrieve the results of the command I am getting nothing.
Connect to server:
public class SSHCommand {
public static String executeRemoteCommand(
String username,
String password,
String hostname,
int port) throws Exception {
JSch jsch = new JSch();
Session session = jsch.getSession(username, hostname, port);
session.setPassword(password);
// Avoid asking for key confirmation
Properties prop = new Properties();
prop.put("StrictHostKeyChecking", "no");
session.setConfig(prop);
session.connect();
// SSH Channel
ChannelExec channelssh = (ChannelExec)
session.openChannel("exec");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
channelssh.setOutputStream(baos);
// Execute command
channelssh.setCommand("ls");
channelssh.connect();
channelssh.disconnect();
return baos.toString();
}
}
Retrieve data:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String TAG = "TESTING";
new AsyncTask<Integer, Void, Void>(){
#Override
protected Void doInBackground(Integer... params) {
try {
Log.d(TAG, SSHCommand.executeRemoteCommand("username", "password", "192.168.0.1", 22));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute(1);
}
}
What am I missing here?
You disconnect immediately after you start the command, before any output is returned.
You have to wait for the "exec" channel to close (it closes once the command finishes).
See the official JSch example for the "exec" channel.
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
System.out.print(new String(tmp, 0, i));
}
if(channel.isClosed()){
if(in.available()>0) continue;
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
Though to allow the command to reliably complete and to collect all output including the errors, see How to read JSch command output?
It worked for me after I put my crafted code after channelssh.connect();
while(true){
if(channelssh.isClosed()){
break;
}
}
So my completed function would be:
public static String executeRemoteCommand(
String username,
String password,
String hostname,
int port) throws Exception {
try{
JSch jsch = new JSch();
Session session = jsch.getSession(username, hostname, 22);
session.setPassword(password);
// Avoid asking for key confirmation
Properties prop = new Properties();
prop.put("StrictHostKeyChecking", "no");
session.setConfig(prop);
session.connect();
// SSH Channel
ChannelExec channelssh = (ChannelExec) session.openChannel("exec");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
channelssh.setOutputStream(baos);
// Execute command
channelssh.setCommand("ls -al");
channelssh.connect();
while(true){
if(channelssh.isClosed()){
break;
}
}
channelssh.disconnect();
return baos.toString();
} catch (Exception e){
Log.e("Some Tag", e.getMessage());
return "ERROR";
}
}
I am trying to copy a file on server from one directory to another one using Jsch. I am using SFTP protocol put and get methods to accomplish this task. I am doing this way as I dont have shell access to the server. Below is my code sample and the exception that I am getting. Can someone please let me know how to resolve it.
OutputStream outputStream = null;
InputStream inputStream = null;
try
{
JSch jsch = new JSch();
session = jsch.getSession(USER,HOST,PORT);
session.setPassword(PASS);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications", "password");
session.setConfig(config);
session.connect();
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
inputStream = channelSftp.get(fromFilename);
channelSftp.put(inputStream,toFilename);
} catch(Exception e){
e.printStackTrace();
} finally {
if(inputStream != null)
inputStream.close();
if(outputStream != null)
outputStream.close();
channelSftp.exit();
channel.disconnect();
session.disconnect();
}
Here is the exception
4: java.io.IOException: error: 4: RequestQueue: unknown request id 12
at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:689)
at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:540)
at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:492)
You have to do the get() operation in a one channel and put() operation in another channel. That works. Here is my code.
public void cp (Session session, String source, String target) throws Exception {
log.info("COMMAND: cp " + source + " " + target);
if (!session.isConnected()) {
log.error("Session is not connected");
throw new Exception("Session is not connected...");
}
Channel upChannel = null;
Channel downChannel = null;
ChannelSftp uploadChannel = null;
ChannelSftp downloadChannel = null;
try {
upChannel = session.openChannel("sftp");
downChannel = session.openChannel("sftp");
upChannel.connect();
downChannel.connect();
uploadChannel = (ChannelSftp) upChannel;
downloadChannel = (ChannelSftp) downChannel;
FileProgressMonitor monitor = new FileProgressMonitor();
InputStream inputStream = uploadChannel.get(source);
downloadChannel.put(inputStream, target, monitor);
} catch (JSchException e) {
log.error("Auth failure", e);
throw new Exception(e);
} finally {
if (upChannel == null || downChannel == null) {
System.out.println("Channel is null ...");
}else if (uploadChannel != null && !uploadChannel.isClosed()){
uploadChannel.exit();
downloadChannel.exit();
uploadChannel.disconnect();
downloadChannel.disconnect();
}else if (!upChannel.isClosed()) {
upChannel.disconnect();
downChannel.disconnect();
}
session.disconnect();
}
}
I can't figure it out how I can send commands via JSch shell channel.
I do this, but it doesn't work:
JSch shell = new JSch();
String command = "cd home/s/src";
Session session = shell.getSession(username, host, port);
MyUserInfo ui = new MyUserInfo();
ui.setPassword(password);
session.setUserInfo(ui);
session.connect();
channel = session.openChannel("shell");
fromServer = new BufferedReader(new InputStreamReader(channel.getInputStream()));
toServer = channel.getOutputStream();
channel.connect();
toServer.write((command + "\r\n").getBytes());
toServer.flush();
and then I read input like this:
StringBuilder builder = new StringBuilder();
int count = 0;
String line = "";
while(line != null) {
line = fromServer.readLine();
builder.append(line).append("\n");
if (line.endsWith(".") || line.endsWith(">")){
break;
}
}
String result = builder.toString();
ConsoleOut.println(result);
Try this:
JSch jsch = new JSch();
try
{
Session session = jsch.getSession("root", "192.168.0.1", 22);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
String command = "lsof -i :80";
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true)
{
while (in.available() > 0)
{
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if (channel.isClosed())
{
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try
{
Thread.sleep(1000);
}
catch (Exception ee)
{
}
}
channel.disconnect();
session.disconnect();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
If it hangs at readLine() that means either your "while" is never ending (might be unlikely considering your code), or, readLine() is waiting for its source, namely the IOstream blocks the thread cause available()!=true.
I can't quite troubleshoot your code without seeing your debug info. But as an advice, have you tried PipedIntputStream? The idea is to pipe your console input to "your" output so that you can "write" it. To implement this, you need to initialize the in/out-put.
InputStream in = new PipedInputStream();
PipedOutputStream pin = new PipedOutputStream((PipedInputStream) in);
/**...*/
channel.setInputStream(in);
channel.connect();
/** ...*/
pin.write(myScript.getBytes());
The same goes to your question, how to read console output.
PipedInputStream pout = new PipedInputStream((PipedOutputStream) out);
/**
* ...
*/
BufferedReader consoleOutput = new BufferedReader(new InputStreamReader(pout));
consoleOutput.readLine();
And again, if you are not sure how many lines to read and thus want to use "while", make sure you do something inside while to prevent 1) busy-waiting 2) ending-condition. Example:
while(!end)
{
consoleOutput.mark(32);
if (consoleOutput.read()==0x03) end = true;//End of Text
else
{
consoleOutput.reset();
consoleOutput.readLine();
end = false;
}
}
Following was a quickly written code for my assignment. Not a well done program.
But serves its purpose.
Connects via SSH (using Jsch) to a server (using a Private Key File - mykey.pem)
Creates a shell script (to mount a volume and mkfs)
Runs on the remote machine
All the while you can see the output on your stdout
The code follows:
public class connectSSH {
public void connect(String dnsName, String privKey) throws IOException {
JSch jSch = new JSch();
try {
//Authenticate through Private Key File
jSch.addIdentity(privKey);
//Give the user and dnsName
Session session = jSch.getSession("root", dnsName, 22);
//Required if not a trusted host
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
System.out.println("Connecting SSH to " + dnsName + " - Please wait for few minutes... ");
session.connect();
//Open a shell
Channel channel=session.openChannel("shell");
channel.setOutputStream(System.out);
//Create a Shell Script
File shellScript = createShellScript();
//Convert the shell script to byte stream
FileInputStream fin = new FileInputStream(shellScript);
byte fileContent[] = new byte[(int)shellScript.length()];
fin.read(fileContent);
InputStream in = new ByteArrayInputStream(fileContent);
//Set the shell script to the channel as input stream
channel.setInputStream(in);
//Connect and have fun!
channel.connect();
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public File createShellScript() {
String filename = "shellscript.sh";
File fstream = new File(filename);
try{
// Create file
PrintStream out = new PrintStream(new FileOutputStream(fstream));
out.println("#!/bin/bash");
out.println("echo \"hi\" > /tmp/test.info");
out.println("echo \"n\" > /tmp/fdisk.in");
out.println("echo \"p\" >> /tmp/fdisk.in");
out.println("echo \"1\" >> /tmp/fdisk.in");
out.println("echo >> /tmp/fdisk.in");
out.println("echo >> /tmp/fdisk.in");
out.println("echo \"w\" >> /tmp/fdisk.in");
out.println("/sbin/fdisk /dev/sdf < /tmp/fdisk.in");
out.println("mkfs.ext3 /dev/sdf1");
out.println("mkdir /usr/myebs");
out.println("mount /dev/sdf1 /usr/myebs");
out.println("partprobe /dev/sdf1");
out.println("echo \"Success\"");
//Close the output stream
out.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
return fstream;
}
public static void main(String[] args) {
connectSSH ssh = new connectSSH();
String privKey = "/Users/neo/Desktop/mykey.pem";
try {
ssh.connect("yourexampleserver.com", privKey);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void executeRemoteCommandAsSudo(String sudoAs, String password,
String command, int delayInSeconds)
{
logger.info("executeRemoteCommandAsSudo started....");
logger.info("sudoAs=" + sudoAs);
logger.info("command=" + command);
logger.info("delayInSeconds=" + delayInSeconds);
Session session = null;
Channel channel = null;
try {
session = getSession();
channel = session.openChannel("exec");
String sudoCommand = "sudo su - " + sudoAs;
((ChannelExec) channel).setCommand(sudoCommand);
((ChannelExec) channel).setPty(true);
channel.connect();
InputStream inputStream = channel.getInputStream();
OutputStream out = channel.getOutputStream();
((ChannelExec) channel).setErrStream(System.err);
out.write((password + "\n").getBytes());
out.flush();
Thread.sleep(1000);
out.write((command + "\n").getBytes());
out.flush();
Thread.sleep(1000 * delayInSeconds);
out.write(("logout" + "\n").getBytes());
out.flush();
Thread.sleep(1000);
logInfo(channel, inputStream);
out.write(("exit" + "\n").getBytes());
out.flush();
out.close();
Thread.sleep(1000);
} catch (Exception ex) {
logger.error(ex.getMessage());
} finally {
session.disconnect();
channel.disconnect();
}
logger.info("executeRemoteCommandAsSudo completed....");
}
private void logInfo(Channel channel, InputStream in)
{
try {
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
logger.info(new String(tmp, 0, i));
}
if (channel.isClosed()) {
logger.info("exit-status: " + channel.getExitStatus());
break;
}
}
} catch (Exception ex) {
logger.error(ex);
}
}
private Session getSession() throws JSchException
{
JSch jsch = new JSch();
logger.info("ftpUser=" + ftpUser);
logger.info("ftpHost=" + ftpHost);
Session session = jsch.getSession(ftpUser, ftpHost, 22);
session.setPassword(ftpPassword);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
return session;
}
With piped input and output streams seems interesting:
JSch jsch = new JSch();
jsch.addIdentity("/home/audrius/.ssh/blablabla", "blablablabla");
String user = "audrius";
String host = "ultrastudio.org";
Session session = jsch.getSession(user, host, 439);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("shell");
PipedInputStream pip = new PipedInputStream(40);
channel.setInputStream(pip);
PipedOutputStream pop = new PipedOutputStream(pip);
PrintStream print = new PrintStream(pop);
channel.setOutputStream(System.out);
print.println("ls");
I realize that this is an old thread, but I have struggled with a similar problem today.
This is my solution.
public class ChannelConsole {
// ================================================
// static fields
// ================================================
// ================================================
// instance fields
// ================================================
private Session session;
// ================================================
// constructors
// ================================================
public ChannelConsole(Session session) {
this.session = session;
}
// ================================================
// getters and setters
// ================================================
// ================================================
// public methods
// ================================================
public String execute(String command) throws JSchException {
command = command.trim() + "\n";
ChannelExec channel = (ChannelExec) this.session.openChannel("exec");
channel.setCommand(command);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
channel.setOutputStream(responseStream);
channel.connect();
try {
awaitChannelClosure(channel);
} catch (InterruptedException e) {
// no one cares
}
String result = responseStream.toString();
closeQuietly(responseStream);
return result;
}
// ================================================
// private methods
// ================================================
private void awaitChannelClosure(ChannelExec channel) throws InterruptedException {
while (channel.isConnected()) {
Thread.sleep(100);
}
}
private static void closeQuietly(Closeable closeable) {
if (closeable == null) {
return;
}
try {
closeable.close();
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
Using this class you can just do something like :
shell = new ChannelConsole(this.session);
String result = shell.execute("quota -v; echo; echo \"Disk storage information:\"; df -hk")
try this
Channel channel=session.openChannel("shell");
OutputStream ops = channel.getOutputStream();
PrintStream ps = new PrintStream(ops, true);
channel.connect();
ps.println("mkdir folder");
ps.println("dir");
//give commands to be executed inside println.and can have any no of commands sent.
ps.close();
InputStream in=channel.getInputStream();
byte[] bt=new byte[1024];
while(true)
{
while(in.available()>0)
{
int i=in.read(bt, 0, 1024);
if(i<0)
break;
String str=new String(bt, 0, i);
//displays the output of the command executed.
System.out.print(str);
}
if(channel.isClosed())
{
break;
}
Thread.sleep(1000);
channel.disconnect();
session.disconnect();
}
Usage:
String remoteCommandOutput = exec("ssh://user:pass#host/work/dir/path", "ls -t | head -n1");
String remoteShellOutput = shell("ssh://user:pass#host/work/dir/path", "ls")
shell("ssh://user:pass#host/work/dir/path", "ls", System.out)
shell("ssh://user:pass#host", System.in, System.out);
Implementation
When using JSch you have to use an InputStream for communication from your SSH client to the server and an OutputStream back from the server to the client. That is probably not very intuitive.
The following examples use piped streams to provide a more flexible API.
Create a JSch session ...
Session session = new JSch().getSession("user", "localhost", port);
session.setPassword("secret");
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
If you want to send multiple commands to a shell you should use the ChannelShell as follows:
ChannelShell channel = (ChannelShell) session.openChannel("shell");
PipedInputStream pis = new PipedInputStream();
channel.setInputStream(pis);
PipedOutputStream pos = new PipedOutputStream();
channel.setOutputStream(pos);
channel.connect();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new PipedOutputStream(pis)));
writer.write("echo Hello World\n");
writer.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(pos)));
String line = reader.readLine(); // blocking IO
assertEquals("Hello World", line);
With the help of an ByteArrayOutputStream you can also communicate in a non-blocking way:
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.setInputStream(new ByteArrayInputStream("echo Hello World\n".getBytes()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
channel.setOutputStream(baos);
channel.connect();
sleep(1000); // needed because of non-blocking IO
String line = baos.toString();
assertEquals("Hello World\n", line);
If you just want to send one command the ChannelExec is enough. As you can see the output stream works in the same way like before:
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("echo Hello World");
PipedOutputStream pos = new PipedOutputStream();
channel.setOutputStream(pos);
channel.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(pos)));
String line = reader.readLine(); // blocking IO
assertEquals("Hello World", line);
try this code :
JSch jsch=new JSch();
System.out.println("Getting session");
Session session=jsch.getSession("root","10.0.0.0",22);
System.out.println("session is ::::"+session.getHost());
// username and password will be given via UserInfo interface.
UserInfo ui = new MyUserInfo("Lab#123", null);
//UserInfo ui = new MyUserInfo(password, null);
session.setUserInfo(ui);
session.setPassword("Lab#123");
Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(40000);
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand("ls");
channel.connect();
channel.run();
// get I/O streams for remote scp
OutputStream out=channel.getOutputStream();
InputStream in=channel.getInputStream();
String output="";
while (channel.isClosed()!=true) {
try {
output+=streamToString(in);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Output is :::"+output);
channel.disconnect();
session.disconnect();
}
public static String streamToString(InputStream input)throws Exception
{ String output = ""; while(input.available()>0) { output += ((char)(input.read())); } return output; }
public static OutputStream stringToStream(String charset) throws IOException{
byte[] bytes = charset.getBytes();
/*ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
InputStreamReader isr = new InputStreamReader(bais);*/
InputStream is = null;
OutputStream os = null;
try {
is = new ByteArrayInputStream(charset.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//byte[] buf = new byte[1024];
int numRead;
while ( (numRead = is.read(bytes) ) >= 0) {
os.write(bytes, 0, numRead);
}
return os;