Mercurial > 510Connectbot
diff src/ch/ethz/ssh2/Connection.java @ 308:42b15aaa7ac7 ganymed
merge
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 30 Jul 2014 14:21:50 -0700 |
parents | 071eccdff8ea |
children | cdb3c9215a9b |
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/Connection.java Wed Jul 30 13:38:04 2014 -0700 +++ b/src/ch/ethz/ssh2/Connection.java Wed Jul 30 14:21:50 2014 -0700 @@ -58,11 +58,11 @@ * US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b> */ private String softwareversion - = String.format("Ganymed_%s", Version.getSpecification()); + = String.format("Ganymed_%s", Version.getSpecification()); - /* Will be used to generate all random data needed for the current connection. + /* Will be used to generate all random data needed for the current connection. * Note: SecureRandom.nextBytes() is thread safe. - */ + */ private SecureRandom generator; @@ -71,6 +71,7 @@ * * @return The list of supported cipher algorithms by this implementation. */ + public static synchronized String[] getAvailableCiphers() { return BlockCipherFactory.getDefaultCipherList(); } @@ -80,6 +81,7 @@ * * @return The list of supported MAC algorthims by this implementation. */ + public static synchronized String[] getAvailableMACs() { return MAC.getMacList(); } @@ -89,6 +91,7 @@ * * @return The list of supported server host key algorthims by this implementation. */ + public static synchronized String[] getAvailableServerHostKeyAlgorithms() { return KexManager.getDefaultServerHostkeyAlgorithmList(); } @@ -99,10 +102,10 @@ private ChannelManager cm; private CryptoWishList cryptoWishList - = new CryptoWishList(); + = new CryptoWishList(); private DHGexParameters dhgexpara - = new DHGexParameters(); + = new DHGexParameters(); private final String hostname; @@ -115,7 +118,7 @@ private HTTPProxyData proxy; private List<ConnectionMonitor> connectionMonitors - = new ArrayList<ConnectionMonitor>(); + = new ArrayList<ConnectionMonitor>(); /** * Prepares a fresh <code>Connection</code> object which can then be used @@ -196,33 +199,33 @@ * disappear in future builds. */ @Deprecated - public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException { - if(tm == null) { + + public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } - if(pem == null) { + if (pem == null) { throw new IllegalArgumentException("pem argument is null"); } authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND()); - return authenticated; } @@ -236,8 +239,9 @@ * @return whether the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb) - throws IOException { + throws IOException { return authenticateWithKeyboardInteractive(user, null, cb); } @@ -271,60 +275,59 @@ * @return whether the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods, - InteractiveCallback cb) throws IOException { - if(cb == null) { + InteractiveCallback cb) throws IOException { + if (cb == null) { throw new IllegalArgumentException("Callback may not ne NULL!"); } - if(tm == null) { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } authenticated = am.authenticateInteractive(user, submethods, cb); - return authenticated; } public synchronized boolean authenticateWithAgent(String user, AgentProxy proxy) throws IOException { - if(tm == null) { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } authenticated = am.authenticatePublicKey(user, proxy); - return authenticated; } @@ -352,33 +355,33 @@ * @return if the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithPassword(String user, String password) throws IOException { - if(tm == null) { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } - if(password == null) { + if (password == null) { throw new IllegalArgumentException("password argument is null"); } authenticated = am.authenticatePassword(user, password); - return authenticated; } @@ -408,32 +411,31 @@ * @return if the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithNone(String user) throws IOException { - if(tm == null) { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } - /* Trigger the sending of the PacketUserauthRequestNone packet */ + /* Trigger the sending of the PacketUserauthRequestNone packet */ /* (if not already done) */ - authenticated = am.authenticateNone(user); - return authenticated; } @@ -475,34 +477,34 @@ * @return whether the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password) - throws IOException { - if(tm == null) { + throws IOException { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument is null"); } - if(pemPrivateKey == null) { + if (pemPrivateKey == null) { throw new IllegalArgumentException("pemPrivateKey argument is null"); } authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND()); - return authenticated; } @@ -578,28 +580,28 @@ * @return whether the connection is now authenticated. * @throws IOException */ + public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password) - throws IOException { - if(pemFile == null) { + throws IOException { + if (pemFile == null) { throw new IllegalArgumentException("pemFile argument is null"); } char[] buff = new char[256]; - CharArrayWriter cw = new CharArrayWriter(); - FileReader fr = new FileReader(pemFile); - while(true) { + while (true) { int len = fr.read(buff); - if(len < 0) { + + if (len < 0) { break; } + cw.write(buff, 0, len); } fr.close(); - return authenticateWithPublicKey(user, cw.toCharArray(), password); } @@ -616,10 +618,12 @@ * @param cmon An object implementing the {@link ConnectionMonitor} interface. * @see ConnectionMonitor */ + public synchronized void addConnectionMonitor(ConnectionMonitor cmon) { - if(!connectionMonitors.contains(cmon)) { + if (!connectionMonitors.contains(cmon)) { connectionMonitors.add(cmon); - if(tm != null) { + + if (tm != null) { tm.setConnectionMonitors(connectionMonitors); } } @@ -631,11 +635,14 @@ * @param cmon * @return whether the monitor could be removed */ + public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon) { boolean existed = connectionMonitors.remove(cmon); - if(tm != null) { + + if (tm != null) { tm.setConnectionMonitors(connectionMonitors); } + return existed; } @@ -661,27 +668,32 @@ * you don't need a connection anymore - otherwise the receiver thread may * run forever. */ + public synchronized void close() { - if(cm != null) { + if (cm != null) { cm.closeAllChannels(); } - if(tm != null) { + + if (tm != null) { tm.close(); tm = null; } + am = null; cm = null; authenticated = false; } public synchronized void close(IOException t) { - if(cm != null) { + if (cm != null) { cm.closeAllChannels(); } - if(tm != null) { + + if (tm != null) { tm.close(t); tm = null; } + am = null; cm = null; authenticated = false; @@ -693,6 +705,7 @@ * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. * @throws IOException */ + public synchronized ConnectionInfo connect() throws IOException { return connect(null, 0, 0); } @@ -703,6 +716,7 @@ * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. * @throws IOException */ + public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException { return connect(verifier, 0, 0); } @@ -768,33 +782,35 @@ * contains the details returned by the proxy. If the proxy is buggy and does * not return a proper HTTP response, then a normal IOException is thrown instead. */ + public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout) - throws IOException { + throws IOException { final class TimeoutState { boolean isCancelled = false; boolean timeoutSocketClosed = false; } - if(tm != null) { + if (tm != null) { throw new IllegalStateException(String.format("Connection to %s is already in connected state", hostname)); } - if(connectTimeout < 0) { + if (connectTimeout < 0) { throw new IllegalArgumentException("connectTimeout must be non-negative!"); } - if(kexTimeout < 0) { + if (kexTimeout < 0) { throw new IllegalArgumentException("kexTimeout must be non-negative!"); } final TimeoutState state = new TimeoutState(); - if(null == proxy) { + if (null == proxy) { tm = new ClientTransportManager(new Socket()); } else { tm = new HTTPProxyClientTransportManager(new Socket(), proxy); } + tm.setSoTimeout(connectTimeout); tm.setTcpNoDelay(tcpNoDelay); tm.setConnectionMonitors(connectionMonitors); @@ -802,68 +818,67 @@ try { TimeoutToken token = null; - if(kexTimeout > 0) { + if (kexTimeout > 0) { final Runnable timeoutHandler = new Runnable() { - public void run() { - synchronized(state) { - if(state.isCancelled) { + public void run() { + synchronized (state) { + if (state.isCancelled) { return; } + state.timeoutSocketClosed = true; tm.close(new SocketTimeoutException("The connect timeout expired")); } } }; - long timeoutHorizont = System.currentTimeMillis() + kexTimeout; - token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler); } tm.connect(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout, - getOrCreateSecureRND()); - - /* Wait until first KEX has finished */ - + getOrCreateSecureRND()); + /* Wait until first KEX has finished */ ConnectionInfo ci = tm.getConnectionInfo(1); - /* Now try to cancel the timeout, if needed */ + /* Now try to cancel the timeout, if needed */ - if(token != null) { + if (token != null) { TimeoutService.cancelTimeoutHandler(token); - /* Were we too late? */ + /* Were we too late? */ - synchronized(state) { - if(state.timeoutSocketClosed) { + synchronized (state) { + if (state.timeoutSocketClosed) { throw new IOException("This exception will be replaced by the one below =)"); } + /* Just in case the "cancelTimeoutHandler" invocation came just a little bit * too late but the handler did not enter the semaphore yet - we can - * still stop it. - */ + * still stop it. + */ state.isCancelled = true; } } return ci; } - catch(SocketTimeoutException e) { + catch (SocketTimeoutException e) { throw e; } - catch(HTTPProxyException e) { + catch (HTTPProxyException e) { throw e; } - catch(IOException e) { + catch (IOException e) { // This will also invoke any registered connection monitors close(e); - synchronized(state) { + synchronized (state) { /* Show a clean exception, not something like "the socket is closed!?!" */ - if(state.timeoutSocketClosed) { + if (state.timeoutSocketClosed) { throw new SocketTimeoutException(String.format("The kexTimeout (%d ms) expired.", kexTimeout)); } } + throw e; } } @@ -883,10 +898,10 @@ * @return A {@link LocalPortForwarder} object. * @throws IOException */ + public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect, - int port_to_connect) throws IOException { + int port_to_connect) throws IOException { this.checkConnection(); - return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect); } @@ -905,10 +920,10 @@ * @return A {@link LocalPortForwarder} object. * @throws IOException */ + public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect, - int port_to_connect) throws IOException { + int port_to_connect) throws IOException { this.checkConnection(); - return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect); } @@ -923,10 +938,10 @@ * @return A {@link LocalStreamForwarder} object. * @throws IOException */ + public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect) - throws IOException { + throws IOException { this.checkConnection(); - return new LocalStreamForwarder(cm, host_to_connect, port_to_connect); } @@ -994,9 +1009,9 @@ * @return A {@link SCPClient} object. * @throws IOException */ + public synchronized SCPClient createSCPClient() throws IOException { this.checkConnection(); - return new SCPClient(this); } @@ -1012,9 +1027,9 @@ * * @throws IOException In case of any failure behind the scenes. */ + public synchronized void forceKeyExchange() throws IOException { this.checkConnection(); - tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null, null); } @@ -1023,6 +1038,7 @@ * * @return the hostname */ + public synchronized String getHostname() { return hostname; } @@ -1032,6 +1048,7 @@ * * @return the TCP port */ + public synchronized int getPort() { return port; } @@ -1044,9 +1061,9 @@ * @return A {@link ConnectionInfo} object. * @throws IOException In case of any failure behind the scenes. */ + public synchronized ConnectionInfo getConnectionInfo() throws IOException { this.checkConnection(); - return tm.getConnectionInfo(1); } @@ -1072,24 +1089,25 @@ * @return a (possibly emtpy) array holding authentication method names. * @throws IOException */ + public synchronized String[] getRemainingAuthMethods(String user) throws IOException { - if(user == null) { + if (user == null) { throw new IllegalArgumentException("user argument may not be NULL!"); } - if(tm == null) { + if (tm == null) { throw new IllegalStateException("Connection is not established!"); } - if(authenticated) { + if (authenticated) { throw new IllegalStateException("Connection is already authenticated!"); } - if(am == null) { + if (am == null) { am = new AuthenticationManager(tm); } - if(cm == null) { + if (cm == null) { cm = new ChannelManager(tm); } @@ -1104,6 +1122,7 @@ * @return <code>true</code> if no further authentication steps are * needed. */ + public synchronized boolean isAuthenticationComplete() { return authenticated; } @@ -1120,10 +1139,12 @@ * @return if the there was a failed authentication step and the last one * was marked as a "partial success". */ + public synchronized boolean isAuthenticationPartialSuccess() { - if(am == null) { + if (am == null) { return false; } + return am.getPartialSuccess(); } @@ -1138,20 +1159,24 @@ * @return if the specified authentication method is currently available. * @throws IOException */ + public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException { String methods[] = getRemainingAuthMethods(user); - for(final String m : methods) { - if(m.compareTo(method) == 0) { + + for (final String m : methods) { + if (m.compareTo(method) == 0) { return true; } } + return false; } private SecureRandom getOrCreateSecureRND() { - if(generator == null) { + if (generator == null) { generator = new SecureRandom(); } + return generator; } @@ -1163,9 +1188,9 @@ * @return A {@link Session} object. * @throws IOException */ + public synchronized Session openSession() throws IOException { this.checkConnection(); - return new Session(cm, getOrCreateSecureRND()); } @@ -1177,12 +1202,11 @@ * * @throws IOException */ + public synchronized void sendIgnorePacket() throws IOException { SecureRandom rnd = getOrCreateSecureRND(); - byte[] data = new byte[rnd.nextInt(16)]; rnd.nextBytes(data); - sendIgnorePacket(data); } @@ -1193,17 +1217,17 @@ * * @throws IOException */ + public synchronized void sendIgnorePacket(byte[] data) throws IOException { this.checkConnection(); - PacketIgnore pi = new PacketIgnore(data); - tm.sendMessage(pi.getPayload()); } /** * Controls whether compression is used on the link or not. */ + public synchronized void setCompression(String[] algorithms) { CompressionFactory.checkCompressorList(algorithms); cryptoWishList.c2s_comp_algos = algorithms; @@ -1215,17 +1239,19 @@ } public synchronized void disableCompression() { - cryptoWishList.c2s_comp_algos = new String[]{"none"}; - cryptoWishList.s2c_comp_algos = new String[]{"none"}; + cryptoWishList.c2s_comp_algos = new String[] {"none"}; + cryptoWishList.s2c_comp_algos = new String[] {"none"}; } /** * Unless you know what you are doing, you will never need this. */ + public synchronized void setClient2ServerCiphers(final String[] ciphers) { - if((ciphers == null) || (ciphers.length == 0)) { + if ((ciphers == null) || (ciphers.length == 0)) { throw new IllegalArgumentException(); } + BlockCipherFactory.checkCipherList(ciphers); cryptoWishList.c2s_enc_algos = ciphers; } @@ -1233,6 +1259,7 @@ /** * Unless you know what you are doing, you will never need this. */ + public synchronized void setClient2ServerMACs(final String[] macs) { MAC.checkMacList(macs); cryptoWishList.c2s_mac_algos = macs; @@ -1245,8 +1272,9 @@ * * @param dgp {@link DHGexParameters}, non null. */ + public synchronized void setDHGexParameters(DHGexParameters dgp) { - if(dgp == null) { + if (dgp == null) { throw new IllegalArgumentException(); } @@ -1256,6 +1284,7 @@ /** * Unless you know what you are doing, you will never need this. */ + public synchronized void setServer2ClientCiphers(final String[] ciphers) { BlockCipherFactory.checkCipherList(ciphers); cryptoWishList.s2c_enc_algos = ciphers; @@ -1264,6 +1293,7 @@ /** * Unless you know what you are doing, you will never need this. */ + public synchronized void setServer2ClientMACs(final String[] macs) { MAC.checkMacList(macs); cryptoWishList.s2c_mac_algos = macs; @@ -1281,6 +1311,7 @@ * the entry at index 0 is the most preferred one. You must specify * at least one entry. */ + public synchronized void setServerHostKeyAlgorithms(final String[] algos) { KexManager.checkServerHostkeyAlgorithmsList(algos); cryptoWishList.serverHostKeyAlgorithms = algos; @@ -1296,9 +1327,11 @@ * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method. * @throws IOException */ + public synchronized void setTCPNoDelay(boolean enable) throws IOException { tcpNoDelay = enable; - if(tm != null) { + + if (tm != null) { tm.setTcpNoDelay(enable); } } @@ -1363,11 +1396,12 @@ * @param targetPort the target port * @throws IOException */ + public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress, - int targetPort) throws IOException { + int targetPort) throws IOException { this.checkConnection(); - if((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) { + if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) { throw new IllegalArgumentException(); } @@ -1384,9 +1418,9 @@ * @throws IOException if the remote side refuses the cancel request or another low * level error occurs (e.g., the underlying connection is closed) */ + public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException { this.checkConnection(); - cm.requestCancelGlobalForward(bindPort); } @@ -1399,18 +1433,21 @@ * * @param rnd a SecureRandom instance */ + public synchronized void setSecureRandom(SecureRandom rnd) { - if(rnd == null) { + if (rnd == null) { throw new IllegalArgumentException(); } + this.generator = rnd; } private void checkConnection() throws IllegalStateException { - if(tm == null) { + if (tm == null) { throw new IllegalStateException("You need to establish a connection first."); } - if(!authenticated) { + + if (!authenticated) { throw new IllegalStateException("The connection is not authenticated."); } }