sshj: How to pipe input to automated host-side script - java

So, here's the situation:
I would like to use the sshj library to connect to a host which automatically runs a script on connection. Let's say the script merely logs whatever json formated input it receives. In the terminal I can run something like:
echo '{ "name" : "Hubert", "status" : "alive" }' | ssh -i ~/.ssh/id_ed25519 user#host.com
and upon connection the host would log the info { "name" : "Hubert", "status" : "alive" }.
What would an (equivalent) implementation of the above command look like in sshj?

Okay, I am not 100% sure whether all I do in the following code is entirely necessary, but it works for me:
final SSHClient ssh = new SSHClient();
/*
* Connect to host and authenticate
*/
try (Session session = ssh.startSession()){
// open a shell on host
final Shell shl = session.startShell();
// just a thread to stream stdout of host
Thread t = new Thread() {
#Override
public void run() {
try {
InputStream in = shl.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println("## " + line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
// another thread to stream stderr of host
Thread err_t = new Thread() {
#Override
public void run() {
try {
InputStream in = shl.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println("## " + line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
err_t.start();
// you might want to escape the input string
String input = "Some String";
byte[] data = input.getBytes();
// getOutputStream() corresponds to the hosts stdin
OutputStream out = shl.getOutputStream();
out.write(data);
// ensure all written bytes get flushed to host
out.flush();
out.close();
shl.join(5, TimeUnit.SECONDS);
shl.close();
} finally {
ssh.disconnect();
}

Related

Forwarding all input to Java Process

I'm trying to forward the input to the process. It's a minecraft server so I need to send commands to it. I try in this way but it doesn't send anything. (I've also checked the log file)
public static void main(String[] args) throws IOException {
File file = new File("spigot.jar");
if(file.exists()) {
ProcessBuilder builder = new ProcessBuilder("java", "-jar", "spigot.jar");
Process p = builder.start();
new Thread(() -> {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = "";
try {
while((s = br.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(()-> {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String cmd = "";
try {
while((cmd = input.readLine()) != null) {
bw.write(cmd);
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
while(true) {
if(!p.isAlive()) {
System.out.println("Server closed.");
System.exit(0);
}
}
}).start();
} else {
System.out.println("spigot.jar not found.");
System.exit(0);
}
}
EDIT:
I rewrote the code using threads but i'm getting the same problem
Solved.
I need to add "bw.newline()" to send ENTER, and make the server execute my command

Java Socket Communication "deadlock"

Hi I am trying to implement server operating with multiply clients
The problem is that the server does not receive the message from inputstream and wait until it happen. if the client don't close the stream after writing to it the server will continue to wait. After the client send the message, he try to read from the inputstream waiting for response, but the server is waiting for the request. So.. deadlock
This is my client class
public class Client implements Runnable{
...
#Override
public void run() {
BufferedReader is = null;
BufferedWriter os = null;
try(Socket socket = new Socket(address.getHostName(), address.getPort());){
String request = String.format("%s-%d-%s",this.destination, this.desiredPlace, this.paymentMethod.toString());
os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(os, true);
pw.write(request);
pw.flush();
// if I close the stream here the request will be send, but this will close the socket so the I will not receive response.
String response;
while ((response = is.readLine()) != null){
System.out.println(response);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And this is my server class
public void perform() throws IOException, DestionationProcessingException, InterruptedException {
try (ServerSocket server = new ServerSocket(port);) {
StandalonePayDesk offLinePayDesk = new StandalonePayDesk(ticketManager);
this.threadPool.submit(offLinePayDesk);
while (true) {
Socket socket = server.accept();
RequestHandler handler = new RequestHandler(this.threadPool, offLinePayDesk, this.ticketManager);
handler.process(socket);
}
}
}
and RequestHandler class for processing each client
try (BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter writer = new PrintWriter(client.getOutputStream(), true)) {
writer.println("hello");
writer.flush();
String line;
while ((line = reader.readLine()) != null) {
String[] lineTokens = line.split("-");
...
Can anyone help me to solve this problem ?
pw.write(request);
Your client is writing a request but not a line. Your server is reading a line, with readLine(), and will block until the line terminator arrives, which is never, so it will never send a reply, so your client will never receive it, so it will block forever.
Change the above to:
pw.println(request);

Send string over Android app to java Server

I'm using this code. Server and android app.
https://github.com/luugiathuy/Remote-Bluetooth-Android
I can send int commands but I want to send strings for more information
I create the issue in the repository but I want all the help posible
In the server I have this
#Override
public void run() {
try {
// prepare to receive data
InputStream inputStream = mConnection.openInputStream();
System.out.println("waiting for input");
while (true) {
int command = inputStream.read();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, Charsets.UTF_8);
String theString = writer.toString();
System.out.println(theString);
if (command == EXIT_CMD)
{
System.out.println("finish process");
break;
}
processCommand(command);
}
} catch (Exception e) {
e.printStackTrace();
}
}
with this response...
BlueCove version 2.1.1-SNAPSHOT on winsock
04c6093b00001000800000805f9b34fb
waiting for connection...
waiting for connection...
waiting for input
23456789?
finish process
BUT in Android I send "123456789" with this code
public void write(String out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out.getBytes());
}
Few edits...
I comment this line
int command = inputStream.read();
and I get the "full" string this this code
BufferedReader bReader=new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while ((line = bReader.readLine()) != null)
{
System.out.println(line);
}
123456789ÿ
I can eliminate the last char but is not the best...
In my android app I have this
mCommandService.write(editText.getText().toString().trim());
editText.getText().clear();
mCommandService.stop();
If I remove the last line, the ÿ disapear. So I guess that is the stop command. Can I remove that or is native?

Running External Program in Eclipse

I am able to print the output of an external program in Eclipse via the code below (found online, not mine). I would like to be able to pass a command to the program and THEN print the output of the program but I don't know how to pass commands to the program. Any suggestions would be appreciated, thanks!
Code:
String line;
Process p = Runtime.getRuntime().exec("Z:/LPCXpresso/test10/Debug/arm-none-eabi-readelf.exe");
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
p.waitFor();
First I would recommend using ProcessBuilder instead of Runtime.getRuntime().exec(...)
Second to be able to interact with the different streams of the process started you need to do it concurrently, i.e. for each stream create an own Thread where you interact with it.
Here is a sample code wihch illustrates interaction with the command line prompt in windows cmd.exe
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("cmd.exe");
Process proc = pb.start();
// handle each of proc's streams in a separate thread
ExecutorService handlerThreadPool = Executors.newFixedThreadPool(3);
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to write to the stdin of the process
BufferedWriter stdin = new BufferedWriter(
new OutputStreamWriter(proc.getOutputStream()));
// read from our own stdin so we can write it to proc's stdin
BufferedReader myStdin =
new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
do {
line = myStdin.readLine();
stdin.write(String.format("%s%n", line));
stdin.flush();
} while(! "exit".equalsIgnoreCase(line));
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stdout of the process
BufferedReader stdout = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
try {
while(null != (line = stdout.readLine())) {
System.out.printf("[stdout] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stderr of the process
BufferedReader stderr = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
String line;
try {
while(null != (line = stderr.readLine())) {
System.err.printf("[stderr] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
// wait for the process to terminate
int exitCode = proc.waitFor();
System.out.printf("Process terminated with exit code %d%n", exitCode);
handlerThreadPool.shutdown();
}
You could make it simple and redirect of the process stderr to stdout using ProcessBuilder#redirectErrorStream(true) before starting the process and then have only 2 threads, one for input and one for output

Process.getOutputStream() doesn't work?

So I'm starting a Bukkit (Minecraft) server from a GUI.
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.command("java", "-jar", file.getAbsolutePath());
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new DataOutputStream(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
There are no errors, and the server itself starts correctly. The input stream works correctly too, as I get all the input as I should. Now, I have this method to send a command to the server.
public void send(String message) {
try {
output.writeUTF(message + "\n");
output.flush();
} catch (IOException e) {
Logger.logError(e);
}
}
For some reason though, it doesn't work. I'm not sure if I missed a step, or am looking over something, etc. Any help would be greatly appreciated!
I suspect the DataOutputStream is writing data in a non-conventional way towards the OutputStream, try using a PrintWriter object instead.
Consider this:
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new PrintWriter(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
The Send method:
public void send(String message) {
output.println(message);
output.flush();
}
P.S You no longer need the try-catch around the output.println() as PrintWriter's print and println methods don't throw IOException.
From bukkit's plugin perspective (read my comment if you have no clue what this is):
final JavaPlugin Inst = ... //This plugin's object
try(BufferedReader Reader = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")))){
while((Line = Reader.readLine()) != null){
final String L = Line;
Bukkit.getScheduler().runTask(Inst, new Runnable(){
#Override
public void run() {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), L);
}
});
}
}catch(IOException ex){
//Handle this
}

Categories