Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/remote/SshConnector.java @ 699:a483b2b68a2e
Provisional APIs and respective implementation for http, https and ssh remote repositories
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 08 Aug 2013 19:18:50 +0200 |
| parents | 822f3a83ff57 |
| children |
comparison
equal
deleted
inserted
replaced
| 698:822f3a83ff57 | 699:a483b2b68a2e |
|---|---|
| 18 | 18 |
| 19 import java.io.BufferedReader; | 19 import java.io.BufferedReader; |
| 20 import java.io.ByteArrayInputStream; | 20 import java.io.ByteArrayInputStream; |
| 21 import java.io.Closeable; | 21 import java.io.Closeable; |
| 22 import java.io.EOFException; | 22 import java.io.EOFException; |
| 23 import java.io.File; | |
| 24 import java.io.FilterInputStream; | 23 import java.io.FilterInputStream; |
| 25 import java.io.FilterOutputStream; | 24 import java.io.FilterOutputStream; |
| 26 import java.io.IOException; | 25 import java.io.IOException; |
| 27 import java.io.InputStream; | 26 import java.io.InputStream; |
| 28 import java.io.InputStreamReader; | 27 import java.io.InputStreamReader; |
| 29 import java.io.OutputStream; | 28 import java.io.OutputStream; |
| 30 import java.io.SequenceInputStream; | 29 import java.io.SequenceInputStream; |
| 31 import java.net.URI; | |
| 32 import java.util.ArrayList; | 30 import java.util.ArrayList; |
| 33 import java.util.Collection; | 31 import java.util.Collection; |
| 34 import java.util.Collections; | 32 import java.util.Collections; |
| 35 import java.util.List; | 33 import java.util.List; |
| 36 | 34 |
| 35 import org.tmatesoft.hg.auth.HgAuthFailedException; | |
| 36 import org.tmatesoft.hg.auth.HgAuthenticator; | |
| 37 import org.tmatesoft.hg.core.HgRemoteConnectionException; | 37 import org.tmatesoft.hg.core.HgRemoteConnectionException; |
| 38 import org.tmatesoft.hg.core.Nodeid; | 38 import org.tmatesoft.hg.core.Nodeid; |
| 39 import org.tmatesoft.hg.core.SessionContext; | 39 import org.tmatesoft.hg.core.SessionContext; |
| 40 import org.tmatesoft.hg.repo.HgRemoteRepository.Range; | 40 import org.tmatesoft.hg.repo.HgRemoteRepository.Range; |
| 41 import org.tmatesoft.hg.repo.HgRemoteRepository.RemoteDescriptor; | |
| 41 import org.tmatesoft.hg.repo.HgRuntimeException; | 42 import org.tmatesoft.hg.repo.HgRuntimeException; |
| 42 import org.tmatesoft.hg.util.LogFacility.Severity; | 43 import org.tmatesoft.hg.util.LogFacility.Severity; |
| 43 | 44 |
| 44 import com.trilead.ssh2.Connection; | 45 import com.trilead.ssh2.Connection; |
| 45 import com.trilead.ssh2.ConnectionInfo; | |
| 46 import com.trilead.ssh2.Session; | 46 import com.trilead.ssh2.Session; |
| 47 import com.trilead.ssh2.StreamGobbler; | 47 import com.trilead.ssh2.StreamGobbler; |
| 48 | 48 |
| 49 /** | 49 /** |
| 50 * Remote repository via SSH | 50 * Remote repository via SSH |
| 51 * | 51 * |
| 52 * @author Artem Tikhomirov | 52 * @author Artem Tikhomirov |
| 53 * @author TMate Software Ltd. | 53 * @author TMate Software Ltd. |
| 54 */ | 54 */ |
| 55 public class SshConnector implements Connector { | 55 public class SshConnector extends ConnectorBase { |
| 56 private RemoteDescriptor rd; | |
| 56 private SessionContext sessionCtx; | 57 private SessionContext sessionCtx; |
| 57 private URI uri; | |
| 58 private Connection conn; | 58 private Connection conn; |
| 59 private Session session; | 59 private Session session; |
| 60 private int sessionUse; | 60 private int sessionUse; |
| 61 | 61 |
| 62 private StreamGobbler remoteErr, remoteOut; | 62 private StreamGobbler remoteErr, remoteOut; |
| 63 private OutputStream remoteIn; | 63 private OutputStream remoteIn; |
| 64 | 64 |
| 65 public void init(URI uri, SessionContext sessionContext, Object globalConfig) throws HgRuntimeException { | 65 public void init(RemoteDescriptor remote, SessionContext sessionContext, Object globalConfig) throws HgRuntimeException { |
| 66 rd = remote; | |
| 66 sessionCtx = sessionContext; | 67 sessionCtx = sessionContext; |
| 67 this.uri = uri; | 68 setURI(remote.getURI()); |
| 68 } | 69 } |
| 69 | 70 |
| 70 public void connect() throws HgRemoteConnectionException, HgRuntimeException { | 71 public void connect() throws HgAuthFailedException, HgRemoteConnectionException, HgRuntimeException { |
| 71 try { | 72 try { |
| 72 conn = new Connection(uri.getHost(), uri.getPort() == -1 ? 22 : uri.getPort()); | 73 conn = new Connection(uri.getHost(), uri.getPort() == -1 ? 22 : uri.getPort()); |
| 73 conn.connect(); | 74 conn.connect(); |
| 74 } catch (IOException ex) { | 75 authenticateClient(); |
| 75 throw new HgRemoteConnectionException("Failed to establish connection"); | 76 } catch (IOException ex) { |
| 76 } | 77 throw new HgRemoteConnectionException("Failed to establish connection").setServerInfo(getServerLocation()); |
| 77 try { | 78 } |
| 78 conn.authenticateWithPublicKey(System.getProperty("user.name"), new File(System.getProperty("user.home"), ".ssh/id_rsa"), null); | 79 } |
| 79 ConnectionInfo ci = conn.getConnectionInfo(); | 80 |
| 80 System.out.printf("%s %s %s %d %s %s %s\n", ci.clientToServerCryptoAlgorithm, ci.clientToServerMACAlgorithm, ci.keyExchangeAlgorithm, ci.keyExchangeCounter, ci.serverHostKeyAlgorithm, ci.serverToClientCryptoAlgorithm, ci.serverToClientMACAlgorithm); | 81 private void authenticateClient() throws HgAuthFailedException { |
| 81 } catch (IOException ex) { | 82 SshAuthMethod m = new SshAuthMethod(conn); |
| 82 throw new HgRemoteConnectionException("Failed to authenticate", ex).setServerInfo(getServerLocation()); | 83 if (uri.getUserInfo() != null) { |
| 83 } | 84 try { |
| 85 m.tryWithUserInfo(uri.getUserInfo()); | |
| 86 return; | |
| 87 } catch (HgAuthFailedException ex) { | |
| 88 // FALL-THROUGH to try with Authenticator | |
| 89 } | |
| 90 } | |
| 91 HgAuthenticator auth = sessionCtx.getAuthenticator(rd); | |
| 92 auth.authenticate(rd, m); | |
| 84 } | 93 } |
| 85 | 94 |
| 86 public void disconnect() throws HgRemoteConnectionException { | 95 public void disconnect() throws HgRemoteConnectionException { |
| 87 if (session != null) { | 96 if (session != null) { |
| 88 forceSessionClose(); | 97 doSessionClose(); |
| 89 } | 98 } |
| 90 if (conn != null) { | 99 if (conn != null) { |
| 91 conn.close(); | 100 conn.close(); |
| 92 conn = null; | 101 conn = null; |
| 93 } | 102 } |
| 117 assert session != null; | 126 assert session != null; |
| 118 if (sessionUse > 1) { | 127 if (sessionUse > 1) { |
| 119 sessionUse--; | 128 sessionUse--; |
| 120 return; | 129 return; |
| 121 } | 130 } |
| 122 forceSessionClose(); | 131 doSessionClose(); |
| 123 } | 132 } |
| 124 | 133 |
| 125 public String getServerLocation() { | |
| 126 return uri.toString(); // FIXME | |
| 127 } | |
| 128 | |
| 129 public String getCapabilities() throws HgRemoteConnectionException { | 134 public String getCapabilities() throws HgRemoteConnectionException { |
| 130 try { | 135 try { |
| 131 consume(remoteOut); | 136 consume(remoteOut); |
| 132 consume(remoteErr); | 137 consume(remoteErr); |
| 133 remoteIn.write(CMD_HELLO.getBytes()); | 138 remoteIn.write(CMD_HELLO.getBytes()); |
| 289 throw new IOException(String.format("Expected response length instead of %s", sb)); | 294 throw new IOException(String.format("Expected response length instead of %s", sb)); |
| 290 } | 295 } |
| 291 } | 296 } |
| 292 | 297 |
| 293 | 298 |
| 294 private void forceSessionClose() { | 299 private void doSessionClose() { |
| 295 if (session != null) { | 300 if (session != null) { |
| 296 closeQuietly(remoteErr); | 301 closeQuietly(remoteErr); |
| 297 closeQuietly(remoteOut); | 302 closeQuietly(remoteOut); |
| 298 remoteErr = remoteOut = null; | 303 remoteErr = remoteOut = null; |
| 299 closeQuietly(remoteIn); | 304 closeQuietly(remoteIn); |
