Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sending data to stdin of remote process - closing has no effect ->remote process waits indefinitely #553

Closed
jpstotz opened this issue Jan 22, 2020 · 5 comments

Comments

@jpstotz
Copy link
Contributor

jpstotz commented Jan 22, 2020

Hi, i am trying to send some data to the stdin of the remote process via sshj.
The sending itself is not a big problem (using Command.getOutputStream() ), however some commands do not terminate until stdin is closed. In seems like it is impossible to use such commands via sshj as closing the OutputStream doe snot has any effect on the remote stdin.

I created the following simple example to demonstarte the problem.

It executes remotely the command cat which simply prints everything on stdout it receives on stdin. Via sshj I am sending the data "Line1\nLine2\nLine3\n" to it and I see that this works as the listening thread prints the received lines correctly.
However in the end this always end in an ConnectionException: Timeout expired as the remote cat process does not terminate because stdin is not closed.

What do I have to send to close the stdin on remote side after the sent data has been received and processed by cat (note this just an example. I want to send larger data to a tar process to extract it on remote side without saving the tar file first)?

	try (Session session = ssh.startSession()) {
		final Command cmd = session.exec("cat");

		Thread t = new Thread() {

			@Override
			public void run() {
				try {
					InputStream in = cmd.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();

		byte[] data = "Line1\nLine2\nLine3\n".getBytes();
		OutputStream out = cmd.getOutputStream();
		out.write(data);
		out.flush();
		out.close(); // this should close stdin on remote side but it doesn't do

		// cmd.getInputStream()
		cmd.join(5, TimeUnit.SECONDS);
		System.out.println("\n** exit status: " + cmd.getExitStatus());
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		ssh.disconnect();
	}
@jpstotz
Copy link
Contributor Author

jpstotz commented Jan 22, 2020

Based on the commented out line in ChannelOutputStream.close() I got some new ideas:

https://github.com/hierynomus/sshj/blob/master/src/main/java/net/schmizz/sshj/connection/channel/ChannelOutputStream.java#L166

Git blame has pointed me to #143 in which this line was commented out, reverted, commented out again and so on. In the end #143 has been closed with that line still commented out (what I don't understand as the issue is therefore IMHO not solved).

If i get the discussion of #143 correctly the result was that mostly sending an CHANNEL_EOF is redundant, but if you turn it around this means that is some cases (like the one I describe here) it is not redundant or to be precises it is necessary to send this package!

Therefore I still don't understand why nobody implemented an simple alternative way to send this packet.

@kholoudasem
Copy link

kholoudasem commented Sep 7, 2021

Hello @jpstotz ,
Did you manage to find a working solution for:
"send larger data to a tar process to extract it on remote side without saving the tar file first" ? as I'm trying to do the same.

@jpstotz
Copy link
Contributor Author

jpstotz commented Sep 7, 2021

@kholoudasem If I remember correctly I tried to optimize a process that uses temporary files on the ssh-server side. As you can read in the linked PR #554 I tried to get the necessary changes into sshj but the whole process stalled. To my feeling hierynomus does not want to touch that code for an unknown reason.

Therefore I have to answer your question with no, I wasn't able to find a solution using a non-modified version of sshj.
Feel free to use the PR or this issue to discuss the topic with hierynomus, may be you have more luck in making him understand why the current sshj code should be improved to allow this use case.

@kholoudasem
Copy link

@jpstotz I found one of the workarounds in PR #554 as:
ssh.getTransport().write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(session.getRecipient()));
So that the outstream is closed, but still I don't know how can I use that to tar a large directory and redirect it to remote host without saving it. I posted another PR #719, but no reply yet.

@jpstotz
Copy link
Contributor Author

jpstotz commented Sep 8, 2021

Just don't use the -f option of tar. Then the created tar archive is written to stdout and you can receive it on the other side of the ssh session.

hierynomus added a commit that referenced this issue Sep 27, 2021
Signed-off-by: Jeroen van Erp <jeroen@hierynomus.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants