1/*
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
3 * Please refer to the LICENSE.txt for licensing details.
4 */
5import java.io.IOException;
6import java.io.InputStream;
7
8import ch.ethz.ssh2.ChannelCondition;
9import ch.ethz.ssh2.Connection;
10import ch.ethz.ssh2.Session;
11
12public class SingleThreadStdoutStderr
13{
14	public static void main(String[] args)
15	{
16		String hostname = "127.0.0.1";
17		String username = "joe";
18		String password = "joespass";
19
20		try
21		{
22			/* Create a connection instance */
23
24			Connection conn = new Connection(hostname);
25
26			/* Now connect */
27
28			conn.connect();
29
30			/* Authenticate */
31
32			boolean isAuthenticated = conn.authenticateWithPassword(username, password);
33
34			if (isAuthenticated == false)
35				throw new IOException("Authentication failed.");
36
37			/* Create a session */
38
39			Session sess = conn.openSession();
40
41			sess.execCommand("echo \"Huge amounts of text on STDOUT\"; echo \"Huge amounts of text on STDERR\" >&2");
42
43			/*
44			 * Advanced:
45			 * The following is a demo on how one can read from stdout and
46			 * stderr without having to use two parallel worker threads (i.e.,
47			 * we don't use the Streamgobblers here) and at the same time not
48			 * risking a deadlock (due to a filled SSH2 channel window, caused
49			 * by the stream which you are currently NOT reading from =).
50			 */
51
52			/* Don't wrap these streams and don't let other threads work on
53			 * these streams while you work with Session.waitForCondition()!!!
54			 */
55
56			InputStream stdout = sess.getStdout();
57			InputStream stderr = sess.getStderr();
58
59			byte[] buffer = new byte[8192];
60
61			while (true)
62			{
63				if ((stdout.available() == 0) && (stderr.available() == 0))
64				{
65					/* Even though currently there is no data available, it may be that new data arrives
66					 * and the session's underlying channel is closed before we call waitForCondition().
67					 * This means that EOF and STDOUT_DATA (or STDERR_DATA, or both) may
68					 * be set together.
69					 */
70
71					int conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA
72							| ChannelCondition.EOF, 2000);
73
74					/* Wait no longer than 2 seconds (= 2000 milliseconds) */
75
76					if ((conditions & ChannelCondition.TIMEOUT) != 0)
77					{
78						/* A timeout occured. */
79						throw new IOException("Timeout while waiting for data from peer.");
80					}
81
82					/* Here we do not need to check separately for CLOSED, since CLOSED implies EOF */
83
84					if ((conditions & ChannelCondition.EOF) != 0)
85					{
86						/* The remote side won't send us further data... */
87
88						if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0)
89						{
90							/* ... and we have consumed all data in the local arrival window. */
91							break;
92						}
93					}
94
95					/* OK, either STDOUT_DATA or STDERR_DATA (or both) is set. */
96
97					// You can be paranoid and check that the library is not going nuts:
98					// if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0)
99					//	throw new IllegalStateException("Unexpected condition result (" + conditions + ")");
100				}
101
102				/* If you below replace "while" with "if", then the way the output appears on the local
103				 * stdout and stder streams is more "balanced". Addtionally reducing the buffer size
104				 * will also improve the interleaving, but performance will slightly suffer.
105				 * OKOK, that all matters only if you get HUGE amounts of stdout and stderr data =)
106				 */
107
108				while (stdout.available() > 0)
109				{
110					int len = stdout.read(buffer);
111					if (len > 0) // this check is somewhat paranoid
112						System.out.write(buffer, 0, len);
113				}
114
115				while (stderr.available() > 0)
116				{
117					int len = stderr.read(buffer);
118					if (len > 0) // this check is somewhat paranoid
119						System.err.write(buffer, 0, len);
120				}
121			}
122
123			/* Close this session */
124
125			sess.close();
126
127			/* Close the connection */
128
129			conn.close();
130
131		}
132		catch (IOException e)
133		{
134			e.printStackTrace(System.err);
135			System.exit(2);
136		}
137	}
138}
139