1 /* 2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. 3 * Please refer to the LICENSE.txt for licensing details. 4 */ 5 import java.io.IOException; 6 import java.io.InputStream; 7 8 import ch.ethz.ssh2.ChannelCondition; 9 import ch.ethz.ssh2.Connection; 10 import ch.ethz.ssh2.Session; 11 12 public class SingleThreadStdoutStderr 13 { main(String[] args)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