mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-08 08:10:55 +03:00
minor changes, reformat etc.
This commit is contained in:
@@ -67,16 +67,16 @@ public interface Config {
|
|||||||
List<Factory.Named<MAC>> getMACFactories();
|
List<Factory.Named<MAC>> getMACFactories();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the {@link net.schmizz.sshj.transport.random.Random} factory.
|
* Retrieve the {@link Random} factory.
|
||||||
*
|
*
|
||||||
* @return the {@link net.schmizz.sshj.transport.random.Random} factory
|
* @return the {@link Random} factory
|
||||||
*/
|
*/
|
||||||
Factory<Random> getRandomFactory();
|
Factory<Random> getRandomFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the list of named factories for {@link net.schmizz.sshj.signature.Signature}
|
* Retrieve the list of named factories for {@link Signature}
|
||||||
*
|
*
|
||||||
* @return a list of named {@link net.schmizz.sshj.signature.Signature} factories
|
* @return a list of named {@link Signature} factories
|
||||||
*/
|
*/
|
||||||
List<Factory.Named<Signature>> getSignatureFactories();
|
List<Factory.Named<Signature>> getSignatureFactories();
|
||||||
|
|
||||||
@@ -87,49 +87,49 @@ public interface Config {
|
|||||||
String getVersion();
|
String getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.transport.cipher.Cipher}.
|
* Set the named factories for {@link Cipher}.
|
||||||
*
|
*
|
||||||
* @param cipherFactories a list of named factories
|
* @param cipherFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
void setCipherFactories(List<Factory.Named<Cipher>> cipherFactories);
|
void setCipherFactories(List<Factory.Named<Cipher>> cipherFactories);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.transport.compression.Compression}.
|
* Set the named factories for {@link Compression}.
|
||||||
*
|
*
|
||||||
* @param compressionFactories a list of named factories
|
* @param compressionFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
void setCompressionFactories(List<Factory.Named<Compression>> compressionFactories);
|
void setCompressionFactories(List<Factory.Named<Compression>> compressionFactories);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.userauth.keyprovider.FileKeyProvider}.
|
* Set the named factories for {@link FileKeyProvider}.
|
||||||
*
|
*
|
||||||
* @param fileKeyProviderFactories a list of named factories
|
* @param fileKeyProviderFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
void setFileKeyProviderFactories(List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories);
|
void setFileKeyProviderFactories(List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.transport.kex.KeyExchange}.
|
* Set the named factories for {@link KeyExchange}.
|
||||||
*
|
*
|
||||||
* @param kexFactories a list of named factories
|
* @param kexFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
void setKeyExchangeFactories(List<Factory.Named<KeyExchange>> kexFactories);
|
void setKeyExchangeFactories(List<Factory.Named<KeyExchange>> kexFactories);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.transport.mac.MAC}.
|
* Set the named factories for {@link MAC}.
|
||||||
*
|
*
|
||||||
* @param macFactories a list of named factories
|
* @param macFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
void setMACFactories(List<Factory.Named<MAC>> macFactories);
|
void setMACFactories(List<Factory.Named<MAC>> macFactories);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the factory for {@link net.schmizz.sshj.transport.random.Random}.
|
* Set the factory for {@link Random}.
|
||||||
*
|
*
|
||||||
* @param randomFactory the factory
|
* @param randomFactory the factory
|
||||||
*/
|
*/
|
||||||
void setRandomFactory(Factory<Random> randomFactory);
|
void setRandomFactory(Factory<Random> randomFactory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the named factories for {@link net.schmizz.sshj.signature.Signature}.
|
* Set the named factories for {@link Signature}.
|
||||||
*
|
*
|
||||||
* @param signatureFactories a list of named factories
|
* @param signatureFactories a list of named factories
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -99,8 +99,7 @@ import java.util.List;
|
|||||||
* <p/>
|
* <p/>
|
||||||
* {@link #startSession()} caters to the most typical use case of starting a {@code session} channel and executing a
|
* {@link #startSession()} caters to the most typical use case of starting a {@code session} channel and executing a
|
||||||
* remote command, starting a subsystem, etc. If you wish to request X11 forwarding for some session, first {@link
|
* remote command, starting a subsystem, etc. If you wish to request X11 forwarding for some session, first {@link
|
||||||
* #registerX11Forwarder(net.schmizz.sshj.connection.channel.forwarded.ConnectListener) register} a {@link
|
* #registerX11Forwarder(ConnectListener) register} a {@link ConnectListener} for {@code x11} channels.
|
||||||
* net.schmizz.sshj.connection.channel.forwarded.ConnectListener} for {@code x11} channels.
|
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link #newLocalPortForwarder Local} and {@link #getRemotePortForwarder() remote} port forwarding is possible. There
|
* {@link #newLocalPortForwarder Local} and {@link #getRemotePortForwarder() remote} port forwarding is possible. There
|
||||||
* are also utility method for easily creating {@link #newSCPFileTransfer SCP} and {@link #newSFTPClient() SFTP}
|
* are also utility method for easily creating {@link #newSCPFileTransfer SCP} and {@link #newSFTPClient() SFTP}
|
||||||
@@ -127,7 +126,9 @@ import java.util.List;
|
|||||||
* Where a password or passphrase is required, if you're extra-paranoid use the {@code char[]} based method. The {@code
|
* Where a password or passphrase is required, if you're extra-paranoid use the {@code char[]} based method. The {@code
|
||||||
* char[]} will be blanked out after use.
|
* char[]} will be blanked out after use.
|
||||||
*/
|
*/
|
||||||
public class SSHClient extends SocketClient implements SessionFactory {
|
public class SSHClient
|
||||||
|
extends SocketClient
|
||||||
|
implements SessionFactory {
|
||||||
|
|
||||||
/** Default port for SSH */
|
/** Default port for SSH */
|
||||||
public static final int DEFAULT_PORT = 22;
|
public static final int DEFAULT_PORT = 22;
|
||||||
@@ -180,7 +181,7 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @param port the port for which the {@code fingerprint} applies
|
* @param port the port for which the {@code fingerprint} applies
|
||||||
* @param fingerprint expected fingerprint in colon-delimited format (16 octets in hex delimited by a colon)
|
* @param fingerprint expected fingerprint in colon-delimited format (16 octets in hex delimited by a colon)
|
||||||
*
|
*
|
||||||
* @see net.schmizz.sshj.common.SecurityUtils#getFingerprint
|
* @see SecurityUtils#getFingerprint
|
||||||
*/
|
*/
|
||||||
public void addHostKeyVerifier(final String host, final int port, final String fingerprint) {
|
public void addHostKeyVerifier(final String host, final int port, final String fingerprint) {
|
||||||
addHostKeyVerifier(new HostKeyVerifier() {
|
addHostKeyVerifier(new HostKeyVerifier() {
|
||||||
@@ -199,7 +200,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void auth(String username, AuthMethod... methods) throws UserAuthException, TransportException {
|
public void auth(String username, AuthMethod... methods)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
assert isConnected();
|
||||||
auth(username, Arrays.<AuthMethod>asList(methods));
|
auth(username, Arrays.<AuthMethod>asList(methods));
|
||||||
}
|
}
|
||||||
@@ -213,7 +215,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void auth(String username, Iterable<AuthMethod> methods) throws UserAuthException, TransportException {
|
public void auth(String username, Iterable<AuthMethod> methods)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
assert isConnected();
|
||||||
auth.authenticate(username, conn, methods);
|
auth.authenticate(username, conn, methods);
|
||||||
}
|
}
|
||||||
@@ -228,7 +231,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPassword(String username, char[] password) throws UserAuthException, TransportException {
|
public void authPassword(String username, char[] password)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
authPassword(username, PasswordUtils.createOneOff(password));
|
authPassword(username, PasswordUtils.createOneOff(password));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,12 +240,13 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* Authenticate {@code username} using the {@code "password"} authentication method.
|
* Authenticate {@code username} using the {@code "password"} authentication method.
|
||||||
*
|
*
|
||||||
* @param username user to authenticate
|
* @param username user to authenticate
|
||||||
* @param pfinder the {@link net.schmizz.sshj.userauth.password.PasswordFinder} to use for authentication
|
* @param pfinder the {@link PasswordFinder} to use for authentication
|
||||||
*
|
*
|
||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPassword(String username, PasswordFinder pfinder) throws UserAuthException, TransportException {
|
public void authPassword(String username, PasswordFinder pfinder)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
auth(username, new AuthPassword(pfinder));
|
auth(username, new AuthPassword(pfinder));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +259,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPassword(String username, String password) throws UserAuthException, TransportException {
|
public void authPassword(String username, String password)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
authPassword(username, password.toCharArray());
|
authPassword(username, password.toCharArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +275,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username) throws UserAuthException, TransportException {
|
public void authPublickey(String username)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
|
String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
|
||||||
authPublickey(username, base + "id_rsa", base + "id_dsa");
|
authPublickey(username, base + "id_rsa", base + "id_dsa");
|
||||||
}
|
}
|
||||||
@@ -287,7 +294,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username, Iterable<KeyProvider> keyProviders) throws UserAuthException,
|
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
||||||
|
throws UserAuthException,
|
||||||
TransportException {
|
TransportException {
|
||||||
List<AuthMethod> am = new LinkedList<AuthMethod>();
|
List<AuthMethod> am = new LinkedList<AuthMethod>();
|
||||||
for (KeyProvider kp : keyProviders)
|
for (KeyProvider kp : keyProviders)
|
||||||
@@ -308,7 +316,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username, KeyProvider... keyProviders) throws UserAuthException,
|
public void authPublickey(String username, KeyProvider... keyProviders)
|
||||||
|
throws UserAuthException,
|
||||||
TransportException {
|
TransportException {
|
||||||
authPublickey(username, Arrays.<KeyProvider>asList(keyProviders));
|
authPublickey(username, Arrays.<KeyProvider>asList(keyProviders));
|
||||||
}
|
}
|
||||||
@@ -329,7 +338,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws UserAuthException in case of authentication failure
|
* @throws UserAuthException in case of authentication failure
|
||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username, String... locations) throws UserAuthException, TransportException {
|
public void authPublickey(String username, String... locations)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
||||||
for (String loc : locations)
|
for (String loc : locations)
|
||||||
try {
|
try {
|
||||||
@@ -349,7 +359,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* cleanup is done and the thread spawned by the transport layer for dealing with incoming packets is stopped.
|
* cleanup is done and the thread spawned by the transport layer for dealing with incoming packets is stopped.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void disconnect() throws IOException {
|
public void disconnect()
|
||||||
|
throws IOException {
|
||||||
assert isConnected();
|
assert isConnected();
|
||||||
trans.disconnect();
|
trans.disconnect();
|
||||||
super.disconnect();
|
super.disconnect();
|
||||||
@@ -411,7 +422,7 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
/**
|
/**
|
||||||
* Returns a {@link KeyProvider} instance created from a location on the file system where an <em>unencrypted</em>
|
* Returns a {@link KeyProvider} instance created from a location on the file system where an <em>unencrypted</em>
|
||||||
* private key file (does not require a passphrase) can be found. Simply calls {@link #loadKeys(String,
|
* private key file (does not require a passphrase) can be found. Simply calls {@link #loadKeys(String,
|
||||||
* PasswordFinder)} with the {@link net.schmizz.sshj.userauth.password.PasswordFinder} argument as {@code null}.
|
* PasswordFinder)} with the {@link PasswordFinder} argument as {@code null}.
|
||||||
*
|
*
|
||||||
* @param location the location for the key file
|
* @param location the location for the key file
|
||||||
*
|
*
|
||||||
@@ -421,26 +432,27 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* BouncyCastle is not in the classpath
|
* BouncyCastle is not in the classpath
|
||||||
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String location) throws IOException {
|
public KeyProvider loadKeys(String location)
|
||||||
|
throws IOException {
|
||||||
return loadKeys(location, (PasswordFinder) null);
|
return loadKeys(location, (PasswordFinder) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function for createing a {@link KeyProvider} instance from given location on the file system. Creates a
|
* Utility function for createing a {@link KeyProvider} instance from given location on the file system. Creates a
|
||||||
* one-off {@link PasswordFinder} using {@link net.schmizz.sshj.userauth.password.PasswordUtils#createOneOff(char[])},
|
* one-off {@link PasswordFinder} using {@link PasswordUtils#createOneOff(char[])}, and calls {@link
|
||||||
* and calls {@link #loadKeys(String,PasswordFinder)}.
|
* #loadKeys(String,PasswordFinder)}.
|
||||||
*
|
*
|
||||||
* @param location location of the key file
|
* @param location location of the key file
|
||||||
* @param passphrase passphrase as a char-array
|
* @param passphrase passphrase as a char-array
|
||||||
*
|
*
|
||||||
* @return the key provider ready for use in authentication
|
* @return the key provider ready for use in authentication
|
||||||
*
|
*
|
||||||
* @throws net.schmizz.sshj.common.SSHException
|
* @throws SSHException if there was no suitable key provider available for the file format; typically because
|
||||||
* if there was no suitable key provider available for the file format; typically because
|
|
||||||
* BouncyCastle is not in the classpath
|
* BouncyCastle is not in the classpath
|
||||||
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String location, char[] passphrase) throws IOException {
|
public KeyProvider loadKeys(String location, char[] passphrase)
|
||||||
|
throws IOException {
|
||||||
return loadKeys(location, PasswordUtils.createOneOff(passphrase));
|
return loadKeys(location, PasswordUtils.createOneOff(passphrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +471,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* BouncyCastle is not in the classpath
|
* BouncyCastle is not in the classpath
|
||||||
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
* @throws IOException if the key file format is not known, if the file could not be read, etc.
|
||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder) throws IOException {
|
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
|
||||||
|
throws IOException {
|
||||||
File loc = new File(location);
|
File loc = new File(location);
|
||||||
FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
|
FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
|
||||||
FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
||||||
@@ -482,7 +495,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws IOException if the key file format is not known, if the file could not be read etc.
|
* @throws IOException if the key file format is not known, if the file could not be read etc.
|
||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String location, String passphrase) throws IOException {
|
public KeyProvider loadKeys(String location, String passphrase)
|
||||||
|
throws IOException {
|
||||||
return loadKeys(location, passphrase.toCharArray());
|
return loadKeys(location, passphrase.toCharArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +509,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws IOException if there is an error loading from <em>both</em> locations
|
* @throws IOException if there is an error loading from <em>both</em> locations
|
||||||
*/
|
*/
|
||||||
public void loadKnownHosts() throws IOException {
|
public void loadKnownHosts()
|
||||||
|
throws IOException {
|
||||||
boolean loaded = false;
|
boolean loaded = false;
|
||||||
final File sshDir = OpenSSHKnownHosts.detectSSHDir();
|
final File sshDir = OpenSSHKnownHosts.detectSSHDir();
|
||||||
if (sshDir != null) {
|
if (sshDir != null) {
|
||||||
@@ -515,7 +530,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws IOException if there is an error loading from any of these locations
|
* @throws IOException if there is an error loading from any of these locations
|
||||||
*/
|
*/
|
||||||
public void loadKnownHosts(File location) throws IOException {
|
public void loadKnownHosts(File location)
|
||||||
|
throws IOException {
|
||||||
addHostKeyVerifier(new OpenSSHKnownHosts(location));
|
addHostKeyVerifier(new OpenSSHKnownHosts(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +542,7 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
||||||
* listening, this method just creates an instance.
|
* listening, this method just creates an instance.
|
||||||
*
|
*
|
||||||
* @param address defines where the {@link net.schmizz.sshj.connection.channel.direct.LocalPortForwarder} listens
|
* @param address defines where the {@link LocalPortForwarder} listens
|
||||||
* @param host hostname to which the server will forward
|
* @param host hostname to which the server will forward
|
||||||
* @param port the port at {@code hostname} to which the server wil forward
|
* @param port the port at {@code hostname} to which the server wil forward
|
||||||
*
|
*
|
||||||
@@ -534,7 +550,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws IOException if there is an error opening a local server socket
|
* @throws IOException if there is an error opening a local server socket
|
||||||
*/
|
*/
|
||||||
public LocalPortForwarder newLocalPortForwarder(SocketAddress address, String host, int port) throws IOException {
|
public LocalPortForwarder newLocalPortForwarder(SocketAddress address, String host, int port)
|
||||||
|
throws IOException {
|
||||||
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
|
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,8 +566,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @param listener the {@link ConnectListener} that should be delegated the responsibility of handling forwarded
|
* @param listener the {@link ConnectListener} that should be delegated the responsibility of handling forwarded
|
||||||
* {@link X11Channel} 's
|
* {@link X11Channel} 's
|
||||||
*
|
*
|
||||||
* @return an {@link net.schmizz.sshj.connection.channel.forwarded.X11Forwarder} that allows to {@link
|
* @return an {@link X11Forwarder} that allows to {@link X11Forwarder#stop() stop acting} on X11 requests from
|
||||||
* X11Forwarder#stop() stop acting} on X11 requests from server
|
* server
|
||||||
*/
|
*/
|
||||||
public X11Forwarder registerX11Forwarder(ConnectListener listener) {
|
public X11Forwarder registerX11Forwarder(ConnectListener listener) {
|
||||||
X11Forwarder x11f = new X11Forwarder(conn, listener);
|
X11Forwarder x11f = new X11Forwarder(conn, listener);
|
||||||
@@ -570,7 +587,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws IOException if there is an error starting the {@code sftp} subsystem
|
* @throws IOException if there is an error starting the {@code sftp} subsystem
|
||||||
* @see StatefulSFTPClient
|
* @see StatefulSFTPClient
|
||||||
*/
|
*/
|
||||||
public SFTPClient newSFTPClient() throws IOException {
|
public SFTPClient newSFTPClient()
|
||||||
|
throws IOException {
|
||||||
assert isConnected() && isAuthenticated();
|
assert isConnected() && isAuthenticated();
|
||||||
return new SFTPClient(this);
|
return new SFTPClient(this);
|
||||||
}
|
}
|
||||||
@@ -580,11 +598,13 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws TransportException if an error occurs during key exchange
|
* @throws TransportException if an error occurs during key exchange
|
||||||
*/
|
*/
|
||||||
public void rekey() throws TransportException {
|
public void rekey()
|
||||||
|
throws TransportException {
|
||||||
doKex();
|
doKex();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Session startSession() throws ConnectionException, TransportException {
|
public Session startSession()
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
assert isConnected() && isAuthenticated();
|
assert isConnected() && isAuthenticated();
|
||||||
SessionChannel sess = new SessionChannel(conn);
|
SessionChannel sess = new SessionChannel(conn);
|
||||||
sess.open();
|
sess.open();
|
||||||
@@ -602,7 +622,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
* @throws ClassNotFoundException if {@code JZlib} is not in classpath
|
* @throws ClassNotFoundException if {@code JZlib} is not in classpath
|
||||||
* @throws TransportException if an error occurs during renegotiation
|
* @throws TransportException if an error occurs during renegotiation
|
||||||
*/
|
*/
|
||||||
public void useCompression() throws ClassNotFoundException, TransportException {
|
public void useCompression()
|
||||||
|
throws ClassNotFoundException, TransportException {
|
||||||
trans.getConfig().setCompressionFactories(Arrays.asList(
|
trans.getConfig().setCompressionFactories(Arrays.asList(
|
||||||
new DelayedZlibCompression.Factory(),
|
new DelayedZlibCompression.Factory(),
|
||||||
new ZlibCompression.Factory(),
|
new ZlibCompression.Factory(),
|
||||||
@@ -613,7 +634,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
|
|
||||||
/** On connection establishment, also initialize the SSH transport via {@link Transport#init} and {@link #doKex()}. */
|
/** On connection establishment, also initialize the SSH transport via {@link Transport#init} and {@link #doKex()}. */
|
||||||
@Override
|
@Override
|
||||||
protected void onConnect() throws IOException {
|
protected void onConnect()
|
||||||
|
throws IOException {
|
||||||
super.onConnect();
|
super.onConnect();
|
||||||
trans.init(getRemoteHostname(), getRemotePort(), getInputStream(), getOutputStream());
|
trans.init(getRemoteHostname(), getRemotePort(), getInputStream(), getOutputStream());
|
||||||
doKex();
|
doKex();
|
||||||
@@ -624,7 +646,8 @@ public class SSHClient extends SocketClient implements SessionFactory {
|
|||||||
*
|
*
|
||||||
* @throws TransportException if error during kex
|
* @throws TransportException if error during kex
|
||||||
*/
|
*/
|
||||||
protected void doKex() throws TransportException {
|
protected void doKex()
|
||||||
|
throws TransportException {
|
||||||
assert trans.isRunning();
|
assert trans.isRunning();
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import net.schmizz.sshj.common.SSHPacketHandler;
|
|||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
/** Represents a service running on top of the SSH {@link net.schmizz.sshj.transport.Transport transport layer}. */
|
/** Represents a service running on top of the SSH {@link net.schmizz.sshj.transport.Transport transport layer}. */
|
||||||
public interface Service extends SSHPacketHandler, ErrorNotifiable {
|
public interface Service
|
||||||
|
extends SSHPacketHandler, ErrorNotifiable {
|
||||||
|
|
||||||
/** @return The assigned name for this SSH service. */
|
/** @return The assigned name for this SSH service. */
|
||||||
String getName();
|
String getName();
|
||||||
@@ -34,17 +35,20 @@ public interface Service extends SSHPacketHandler, ErrorNotifiable {
|
|||||||
*
|
*
|
||||||
* @throws SSHException if the packet is unexpected and may represent a disruption
|
* @throws SSHException if the packet is unexpected and may represent a disruption
|
||||||
*/
|
*/
|
||||||
void notifyUnimplemented(long seqNum) throws SSHException;
|
void notifyUnimplemented(long seqNum)
|
||||||
|
throws SSHException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request and install this service with the associated transport. Implementations should aim to make this method
|
* Request and install this service with the associated transport. Implementations should aim to make this method
|
||||||
* idempotent by first checking the {@link net.schmizz.sshj.transport.Transport#getService() currently active
|
* idempotent by first checking the {@link net.schmizz.sshj.transport.Transport#getService()} currently active
|
||||||
* service}.
|
* service}.
|
||||||
*
|
*
|
||||||
* @throws TransportException if there is an error sending the service request
|
* @throws TransportException if there is an error sending the service request
|
||||||
*/
|
*/
|
||||||
void request() throws TransportException;
|
void request()
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
void notifyDisconnect() throws SSHException;
|
void notifyDisconnect()
|
||||||
|
throws SSHException;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -48,12 +48,33 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
public class Buffer<T extends Buffer<T>> {
|
public class Buffer<T extends Buffer<T>> {
|
||||||
|
|
||||||
public static class BufferException extends SSHRuntimeException {
|
public static class BufferException
|
||||||
|
extends SSHRuntimeException {
|
||||||
public BufferException(String message) {
|
public BufferException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PlainBuffer
|
||||||
|
extends Buffer<PlainBuffer> {
|
||||||
|
|
||||||
|
public PlainBuffer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlainBuffer(Buffer<?> from) {
|
||||||
|
super(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlainBuffer(byte[] b) {
|
||||||
|
super(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlainBuffer(int size) {
|
||||||
|
super(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The default size for a {@code Buffer} (256 bytes) */
|
/** The default size for a {@code Buffer} (256 bytes) */
|
||||||
public static final int DEFAULT_SIZE = 256;
|
public static final int DEFAULT_SIZE = 256;
|
||||||
|
|
||||||
@@ -473,18 +494,22 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
public T putPublicKey(PublicKey key) {
|
public T putPublicKey(PublicKey key) {
|
||||||
KeyType type = KeyType.fromKey(key);
|
KeyType type = KeyType.fromKey(key);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RSA:
|
case RSA: {
|
||||||
|
final RSAPublicKey rsaKey = (RSAPublicKey) key;
|
||||||
putString(type.toString()) // ssh-rsa
|
putString(type.toString()) // ssh-rsa
|
||||||
.putMPInt(((RSAPublicKey) key).getPublicExponent()) // e
|
.putMPInt(rsaKey.getPublicExponent()) // e
|
||||||
.putMPInt(((RSAPublicKey) key).getModulus()); // n
|
.putMPInt(rsaKey.getModulus()); // n
|
||||||
break;
|
break;
|
||||||
case DSA:
|
}
|
||||||
|
case DSA: {
|
||||||
|
final DSAPublicKey dsaKey = (DSAPublicKey) key;
|
||||||
putString(type.toString()) // ssh-dss
|
putString(type.toString()) // ssh-dss
|
||||||
.putMPInt(((DSAPublicKey) key).getParams().getP()) // p
|
.putMPInt(dsaKey.getParams().getP()) // p
|
||||||
.putMPInt(((DSAPublicKey) key).getParams().getQ()) // q
|
.putMPInt(dsaKey.getParams().getQ()) // q
|
||||||
.putMPInt(((DSAPublicKey) key).getParams().getG()) // g
|
.putMPInt(dsaKey.getParams().getG()) // g
|
||||||
.putMPInt(((DSAPublicKey) key).getY()); // y
|
.putMPInt(dsaKey.getY()); // y
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
}
|
}
|
||||||
@@ -492,7 +517,8 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T putSignature(String sigFormat, byte[] sigData) {
|
public T putSignature(String sigFormat, byte[] sigData) {
|
||||||
return putString(new PlainBuffer().putString(sigFormat).putBytes(sigData).getCompactData());
|
final byte[] sig = new PlainBuffer().putString(sigFormat).putBytes(sigData).getCompactData();
|
||||||
|
return putString(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -509,23 +535,4 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
return "Buffer [rpos=" + rpos + ", wpos=" + wpos + ", size=" + data.length + "]";
|
return "Buffer [rpos=" + rpos + ", wpos=" + wpos + ", size=" + data.length + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PlainBuffer extends Buffer<PlainBuffer> {
|
|
||||||
|
|
||||||
public PlainBuffer() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlainBuffer(Buffer<?> from) {
|
|
||||||
super(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlainBuffer(byte[] b) {
|
|
||||||
super(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlainBuffer(int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ public interface Factory<T> {
|
|||||||
*
|
*
|
||||||
* @param <T> type of object created by this factory
|
* @param <T> type of object created by this factory
|
||||||
*/
|
*/
|
||||||
interface Named<T> extends Factory<T> {
|
interface Named<T>
|
||||||
|
extends Factory<T> {
|
||||||
|
|
||||||
/** Utility functions */
|
/** Utility functions */
|
||||||
public static class Util {
|
public static class Util {
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ import java.io.IOException;
|
|||||||
* Most exceptions in {@code org.apache.commons.net.ssh} are instances of this class. An {@link SSHException} is itself
|
* Most exceptions in {@code org.apache.commons.net.ssh} are instances of this class. An {@link SSHException} is itself
|
||||||
* an {@link IOException} and can be caught like that if this level of granularity is not desired.
|
* an {@link IOException} and can be caught like that if this level of granularity is not desired.
|
||||||
*/
|
*/
|
||||||
public class SSHException extends IOException {
|
public class SSHException
|
||||||
|
extends IOException {
|
||||||
|
|
||||||
public static final ExceptionChainer<SSHException> chainer = new ExceptionChainer<SSHException>() {
|
public static final ExceptionChainer<SSHException> chainer = new ExceptionChainer<SSHException>() {
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ package net.schmizz.sshj.common;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class SSHPacket extends Buffer<SSHPacket> {
|
public class SSHPacket
|
||||||
|
extends Buffer<SSHPacket> {
|
||||||
|
|
||||||
public SSHPacket() {
|
public SSHPacket() {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public interface SSHPacketHandler {
|
|||||||
*
|
*
|
||||||
* @throws SSHException if there is a non-recoverable error
|
* @throws SSHException if there is a non-recoverable error
|
||||||
*/
|
*/
|
||||||
void handle(Message msg, SSHPacket buf) throws SSHException;
|
void handle(Message msg, SSHPacket buf)
|
||||||
|
throws SSHException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
/** Represents unrecoverable exceptions in the {@code org.apache.commons.net.ssh} package. */
|
/** Represents unrecoverable exceptions in the {@code org.apache.commons.net.ssh} package. */
|
||||||
public class SSHRuntimeException extends RuntimeException {
|
public class SSHRuntimeException
|
||||||
|
extends RuntimeException {
|
||||||
|
|
||||||
public SSHRuntimeException() {
|
public SSHRuntimeException() {
|
||||||
this(null, null);
|
this(null, null);
|
||||||
|
|||||||
@@ -52,11 +52,14 @@ import java.security.NoSuchProviderException;
|
|||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.Signature;
|
import java.security.Signature;
|
||||||
|
|
||||||
|
// TODO refactor
|
||||||
|
|
||||||
/** Static utility method relating to security facilities. */
|
/** Static utility method relating to security facilities. */
|
||||||
public class SecurityUtils {
|
public class SecurityUtils {
|
||||||
|
|
||||||
private static class BouncyCastleRegistration {
|
private static class BouncyCastleRegistration {
|
||||||
public void run() throws Exception {
|
public void run()
|
||||||
|
throws Exception {
|
||||||
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
||||||
LOG.info("Trying to register BouncyCastle as a JCE provider");
|
LOG.info("Trying to register BouncyCastle as a JCE provider");
|
||||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||||
@@ -83,8 +86,8 @@ public class SecurityUtils {
|
|||||||
private static Boolean registerBouncyCastle;
|
private static Boolean registerBouncyCastle;
|
||||||
private static boolean registrationDone;
|
private static boolean registrationDone;
|
||||||
|
|
||||||
public static synchronized Cipher getCipher(String transformation) throws NoSuchAlgorithmException,
|
public static synchronized Cipher getCipher(String transformation)
|
||||||
NoSuchPaddingException, NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return Cipher.getInstance(transformation);
|
return Cipher.getInstance(transformation);
|
||||||
@@ -127,8 +130,8 @@ public class SecurityUtils {
|
|||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
public static synchronized KeyAgreement getKeyAgreement(String algorithm) throws NoSuchAlgorithmException,
|
public static synchronized KeyAgreement getKeyAgreement(String algorithm)
|
||||||
NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return KeyAgreement.getInstance(algorithm);
|
return KeyAgreement.getInstance(algorithm);
|
||||||
@@ -146,8 +149,8 @@ public class SecurityUtils {
|
|||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
public static synchronized KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException,
|
public static synchronized KeyFactory getKeyFactory(String algorithm)
|
||||||
NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return KeyFactory.getInstance(algorithm);
|
return KeyFactory.getInstance(algorithm);
|
||||||
@@ -165,8 +168,8 @@ public class SecurityUtils {
|
|||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
public static synchronized KeyPairGenerator getKeyPairGenerator(String algorithm) throws NoSuchAlgorithmException,
|
public static synchronized KeyPairGenerator getKeyPairGenerator(String algorithm)
|
||||||
NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return KeyPairGenerator.getInstance(algorithm);
|
return KeyPairGenerator.getInstance(algorithm);
|
||||||
@@ -184,7 +187,8 @@ public class SecurityUtils {
|
|||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
public static synchronized Mac getMAC(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
|
public static synchronized Mac getMAC(String algorithm)
|
||||||
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return Mac.getInstance(algorithm);
|
return Mac.getInstance(algorithm);
|
||||||
@@ -202,8 +206,8 @@ public class SecurityUtils {
|
|||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
public static synchronized MessageDigest getMessageDigest(String algorithm) throws NoSuchAlgorithmException,
|
public static synchronized MessageDigest getMessageDigest(String algorithm)
|
||||||
NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return MessageDigest.getInstance(algorithm);
|
return MessageDigest.getInstance(algorithm);
|
||||||
@@ -221,8 +225,8 @@ public class SecurityUtils {
|
|||||||
return securityProvider;
|
return securityProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized Signature getSignature(String algorithm) throws NoSuchAlgorithmException,
|
public static synchronized Signature getSignature(String algorithm)
|
||||||
NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
if (getSecurityProvider() == null)
|
if (getSecurityProvider() == null)
|
||||||
return Signature.getInstance(algorithm);
|
return Signature.getInstance(algorithm);
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class StreamCopier extends Thread {
|
public class StreamCopier
|
||||||
|
extends Thread {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(StreamCopier.class);
|
private static final Logger LOG = LoggerFactory.getLogger(StreamCopier.class);
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ public class StreamCopier extends Thread {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing) throws IOException {
|
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing)
|
||||||
|
throws IOException {
|
||||||
long count = 0;
|
long count = 0;
|
||||||
|
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
@@ -64,7 +66,8 @@ public class StreamCopier extends Thread {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String copyStreamToString(InputStream stream) throws IOException {
|
public static String copyStreamToString(InputStream stream)
|
||||||
|
throws IOException {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
int read;
|
int read;
|
||||||
while ((read = stream.read()) != -1)
|
while ((read = stream.read()) != -1)
|
||||||
|
|||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection;
|
package net.schmizz.sshj.connection;
|
||||||
|
|
||||||
@@ -43,16 +23,14 @@ import net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener;
|
|||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
/**
|
/** Connection layer of the SSH protocol. Refer to RFC 254. */
|
||||||
* Connection layer of the SSH protocol.
|
|
||||||
*
|
|
||||||
* @see rfc4254
|
|
||||||
*/
|
|
||||||
public interface Connection {
|
public interface Connection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach a {@link net.schmizz.sshj.connection.channel.Channel} to this connection. A channel must be attached to
|
* Attach a {@link net.schmizz.sshj.connection.channel.Channel} to this connection. A channel must be attached to
|
||||||
* the connection if it is to receive any channel-specific data that is received.
|
* the connection if it is to receive any channel-specific data that is received.
|
||||||
|
*
|
||||||
|
* @param chan
|
||||||
*/
|
*/
|
||||||
void attach(Channel chan);
|
void attach(Channel chan);
|
||||||
|
|
||||||
@@ -60,24 +38,45 @@ public interface Connection {
|
|||||||
* Attach a {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener} to this connection, which
|
* Attach a {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener} to this connection, which
|
||||||
* will be delegated opening of any {@code CHANNEL_OPEN} packets {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener#getChannelType()
|
* will be delegated opening of any {@code CHANNEL_OPEN} packets {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener#getChannelType()
|
||||||
* for which it is responsible}.
|
* for which it is responsible}.
|
||||||
|
*
|
||||||
|
* @param opener
|
||||||
*/
|
*/
|
||||||
void attach(ForwardedChannelOpener opener);
|
void attach(ForwardedChannelOpener opener);
|
||||||
|
|
||||||
/** Forget an attached {@link Channel}. */
|
/**
|
||||||
|
* Forget an attached {@link Channel}.
|
||||||
|
*
|
||||||
|
* @param chan
|
||||||
|
*/
|
||||||
void forget(Channel chan);
|
void forget(Channel chan);
|
||||||
|
|
||||||
/** Forget an attached {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener}. */
|
/**
|
||||||
|
* Forget an attached {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener}.
|
||||||
|
*
|
||||||
|
* @param handler
|
||||||
|
*/
|
||||||
void forget(ForwardedChannelOpener handler);
|
void forget(ForwardedChannelOpener handler);
|
||||||
|
|
||||||
/** Returns an attached {@link Channel} of specified channel-id, or {@code null} if no such channel was attached */
|
/**
|
||||||
|
* Returns an attached {@link Channel} of specified channel-id, or {@code null} if no such channel was attached
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
Channel get(int id);
|
Channel get(int id);
|
||||||
|
|
||||||
/** Wait for the situation that no channels are attached (e.g., got closed). */
|
/**
|
||||||
void join() throws InterruptedException;
|
* Wait for the situation that no channels are attached (e.g., got closed).
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
void join()
|
||||||
|
throws InterruptedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an attached {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener} of specified
|
* @param chanType channel type
|
||||||
* channel-type, or {@code null} if no such channel was attached
|
*
|
||||||
|
* @return an attached {@link ForwardedChannelOpener} of specified channel-type, or {@code null} if no such channel
|
||||||
|
* was attached
|
||||||
*/
|
*/
|
||||||
ForwardedChannelOpener get(String chanType);
|
ForwardedChannelOpener get(String chanType);
|
||||||
|
|
||||||
@@ -97,7 +96,8 @@ public interface Connection {
|
|||||||
* @throws TransportException if there is an error sending the request
|
* @throws TransportException if there is an error sending the request
|
||||||
*/
|
*/
|
||||||
public Future<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
|
public Future<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
|
||||||
byte[] specifics) throws TransportException;
|
byte[] specifics)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a {@code SSH_MSG_OPEN_FAILURE} for specified {@code Reason} and {@code message}.
|
* Send a {@code SSH_MSG_OPEN_FAILURE} for specified {@code Reason} and {@code message}.
|
||||||
@@ -108,7 +108,8 @@ public interface Connection {
|
|||||||
*
|
*
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
void sendOpenFailure(int recipient, OpenFailException.Reason reason, String message) throws TransportException;
|
void sendOpenFailure(int recipient, OpenFailException.Reason reason, String message)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum packet size for the local window this connection recommends to any {@link Channel}'s that ask for
|
* Get the maximum packet size for the local window this connection recommends to any {@link Channel}'s that ask for
|
||||||
|
|||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection;
|
package net.schmizz.sshj.connection;
|
||||||
|
|
||||||
@@ -40,7 +20,8 @@ import net.schmizz.sshj.common.DisconnectReason;
|
|||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
|
|
||||||
/** Connection-layer exception. */
|
/** Connection-layer exception. */
|
||||||
public class ConnectionException extends SSHException {
|
public class ConnectionException
|
||||||
|
extends SSHException {
|
||||||
|
|
||||||
public static final ExceptionChainer<ConnectionException> chainer = new ExceptionChainer<ConnectionException>() {
|
public static final ExceptionChainer<ConnectionException> chainer = new ExceptionChainer<ConnectionException>() {
|
||||||
public ConnectionException chain(Throwable t) {
|
public ConnectionException chain(Throwable t) {
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/** {@link Connection} implementation. */
|
/** {@link Connection} implementation. */
|
||||||
public class ConnectionImpl extends AbstractService implements Connection {
|
public class ConnectionImpl
|
||||||
|
extends AbstractService
|
||||||
|
implements Connection {
|
||||||
|
|
||||||
private final Object internalSynchronizer = new Object();
|
private final Object internalSynchronizer = new Object();
|
||||||
|
|
||||||
@@ -93,7 +95,8 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
openers.put(opener.getChannelType(), opener);
|
openers.put(opener.getChannelType(), opener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Channel getChannel(SSHPacket buffer) throws ConnectionException {
|
private Channel getChannel(SSHPacket buffer)
|
||||||
|
throws ConnectionException {
|
||||||
int recipient = buffer.readInt();
|
int recipient = buffer.readInt();
|
||||||
Channel channel = get(recipient);
|
Channel channel = get(recipient);
|
||||||
if (channel != null)
|
if (channel != null)
|
||||||
@@ -106,7 +109,8 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Message msg, SSHPacket buf) throws SSHException {
|
public void handle(Message msg, SSHPacket buf)
|
||||||
|
throws SSHException {
|
||||||
if (msg.in(91, 100))
|
if (msg.in(91, 100))
|
||||||
getChannel(buf).handle(msg, buf);
|
getChannel(buf).handle(msg, buf);
|
||||||
|
|
||||||
@@ -162,7 +166,8 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
this.windowSize = windowSize;
|
this.windowSize = windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join() throws InterruptedException {
|
public void join()
|
||||||
|
throws InterruptedException {
|
||||||
synchronized (internalSynchronizer) {
|
synchronized (internalSynchronizer) {
|
||||||
while (!channels.isEmpty())
|
while (!channels.isEmpty())
|
||||||
internalSynchronizer.wait();
|
internalSynchronizer.wait();
|
||||||
@@ -174,10 +179,12 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Future<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
|
public Future<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
|
||||||
byte[] specifics) throws TransportException {
|
byte[] specifics)
|
||||||
|
throws TransportException {
|
||||||
synchronized (globalReqFutures) {
|
synchronized (globalReqFutures) {
|
||||||
log.info("Making global request for `{}`", name);
|
log.info("Making global request for `{}`", name);
|
||||||
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name).putBoolean(wantReply).putRawBytes(specifics));
|
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
|
||||||
|
.putBoolean(wantReply).putRawBytes(specifics));
|
||||||
|
|
||||||
Future<SSHPacket, ConnectionException> future = null;
|
Future<SSHPacket, ConnectionException> future = null;
|
||||||
if (wantReply) {
|
if (wantReply) {
|
||||||
@@ -188,7 +195,8 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotGlobalReqResponse(SSHPacket response) throws ConnectionException {
|
private void gotGlobalReqResponse(SSHPacket response)
|
||||||
|
throws ConnectionException {
|
||||||
synchronized (globalReqFutures) {
|
synchronized (globalReqFutures) {
|
||||||
Future<SSHPacket, ConnectionException> gr = globalReqFutures.poll();
|
Future<SSHPacket, ConnectionException> gr = globalReqFutures.poll();
|
||||||
if (gr == null)
|
if (gr == null)
|
||||||
@@ -201,7 +209,8 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotChannelOpen(SSHPacket buf) throws ConnectionException, TransportException {
|
private void gotChannelOpen(SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
final String type = buf.readString();
|
final String type = buf.readString();
|
||||||
log.debug("Received CHANNEL_OPEN for `{}` channel", type);
|
log.debug("Received CHANNEL_OPEN for `{}` channel", type);
|
||||||
if (openers.containsKey(type))
|
if (openers.containsKey(type))
|
||||||
@@ -212,17 +221,19 @@ public class ConnectionImpl extends AbstractService implements Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendOpenFailure(int recipient, Reason reason, String message) throws TransportException {
|
public void sendOpenFailure(int recipient, Reason reason, String message)
|
||||||
trans.write(new SSHPacket(Message.CHANNEL_OPEN_FAILURE) //
|
throws TransportException {
|
||||||
.putInt(recipient) //
|
trans.write(new SSHPacket(Message.CHANNEL_OPEN_FAILURE)
|
||||||
.putInt(reason.getCode()) //
|
.putInt(recipient)
|
||||||
|
.putInt(reason.getCode())
|
||||||
.putString(message));
|
.putString(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyDisconnect() throws SSHException {
|
public void notifyDisconnect()
|
||||||
|
throws SSHException {
|
||||||
super.notifyDisconnect();
|
super.notifyDisconnect();
|
||||||
// wh'about them futures?
|
FutureUtils.alertAll(new ConnectionException("Disconnected."), globalReqFutures);
|
||||||
for (Channel chan : channels.values())
|
for (Channel chan : channels.values())
|
||||||
chan.close();
|
chan.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ import java.util.Queue;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public abstract class AbstractChannel implements Channel {
|
public abstract class AbstractChannel
|
||||||
|
implements Channel {
|
||||||
|
|
||||||
/** Logger */
|
/** Logger */
|
||||||
protected final Logger log;
|
protected final Logger log;
|
||||||
@@ -164,7 +165,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(Message msg, SSHPacket buf) throws ConnectionException, TransportException {
|
public void handle(Message msg, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
|
||||||
case CHANNEL_DATA:
|
case CHANNEL_DATA:
|
||||||
@@ -205,7 +207,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotClose() throws TransportException {
|
private void gotClose()
|
||||||
|
throws TransportException {
|
||||||
log.info("Got close");
|
log.info("Got close");
|
||||||
try {
|
try {
|
||||||
closeAllStreams();
|
closeAllStreams();
|
||||||
@@ -236,7 +239,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
this.autoExpand = autoExpand;
|
this.autoExpand = autoExpand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws ConnectionException, TransportException {
|
public void close()
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
@@ -251,7 +255,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void sendClose() throws TransportException {
|
protected synchronized void sendClose()
|
||||||
|
throws TransportException {
|
||||||
try {
|
try {
|
||||||
if (!closeRequested) {
|
if (!closeRequested) {
|
||||||
log.info("Sending close");
|
log.info("Sending close");
|
||||||
@@ -271,7 +276,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotChannelRequest(SSHPacket buf) throws ConnectionException, TransportException {
|
private void gotChannelRequest(SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
final String reqType = buf.readString();
|
final String reqType = buf.readString();
|
||||||
buf.readBoolean(); // We don't care about the 'want-reply' value
|
buf.readBoolean(); // We don't care about the 'want-reply' value
|
||||||
log.info("Got chan request for `{}`", reqType);
|
log.info("Got chan request for `{}`", reqType);
|
||||||
@@ -289,15 +295,18 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
close.set();
|
close.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void gotExtendedData(int dataTypeCode, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void gotExtendedData(int dataTypeCode, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR, "Extended data not supported on " + type
|
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR, "Extended data not supported on " + type
|
||||||
+ " channel");
|
+ " channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void gotUnknown(Message msg, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void gotUnknown(Message msg, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleRequest(String reqType, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void handleRequest(String reqType, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
trans.write(newBuffer(Message.CHANNEL_FAILURE));
|
trans.write(newBuffer(Message.CHANNEL_FAILURE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +314,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
return new SSHPacket(cmd).putInt(recipient);
|
return new SSHPacket(cmd).putInt(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void receiveInto(ChannelInputStream stream, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void receiveInto(ChannelInputStream stream, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
final int len = buf.readInt();
|
final int len = buf.readInt();
|
||||||
if (len < 0 || len > getLocalMaxPacketSize() || len != buf.available())
|
if (len < 0 || len > getLocalMaxPacketSize() || len != buf.available())
|
||||||
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR, "Bad item length: " + len);
|
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR, "Bad item length: " + len);
|
||||||
@@ -315,7 +325,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
protected synchronized Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
||||||
Buffer.PlainBuffer reqSpecific) throws TransportException {
|
Buffer.PlainBuffer reqSpecific)
|
||||||
|
throws TransportException {
|
||||||
log.info("Sending channel request for `{}`", reqType);
|
log.info("Sending channel request for `{}`", reqType);
|
||||||
trans.write(
|
trans.write(
|
||||||
newBuffer(Message.CHANNEL_REQUEST)
|
newBuffer(Message.CHANNEL_REQUEST)
|
||||||
@@ -332,7 +343,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
return responseEvent;
|
return responseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void gotResponse(boolean success) throws ConnectionException {
|
private synchronized void gotResponse(boolean success)
|
||||||
|
throws ConnectionException {
|
||||||
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
||||||
if (responseEvent != null) {
|
if (responseEvent != null) {
|
||||||
if (success)
|
if (success)
|
||||||
@@ -345,7 +357,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
"Received response to channel request when none was requested");
|
"Received response to channel request when none was requested");
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void gotEOF() throws TransportException {
|
private synchronized void gotEOF()
|
||||||
|
throws TransportException {
|
||||||
log.info("Got EOF");
|
log.info("Got EOF");
|
||||||
eofGot = true;
|
eofGot = true;
|
||||||
eofInputStreams();
|
eofInputStreams();
|
||||||
@@ -358,7 +371,8 @@ public abstract class AbstractChannel implements Channel {
|
|||||||
in.eof();
|
in.eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void sendEOF() throws TransportException {
|
public synchronized void sendEOF()
|
||||||
|
throws TransportException {
|
||||||
try {
|
try {
|
||||||
if (!closeRequested && !eofSent) {
|
if (!closeRequested && !eofSent) {
|
||||||
log.info("Sending EOF");
|
log.info("Sending EOF");
|
||||||
|
|||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
@@ -45,10 +25,12 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/** A channel is the basic medium for application-layer data on top of an SSH transport. */
|
/** A channel is the basic medium for application-layer data on top of an SSH transport. */
|
||||||
public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
public interface Channel
|
||||||
|
extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
||||||
|
|
||||||
/** Direct channels are those that are initiated by us. */
|
/** Direct channels are those that are initiated by us. */
|
||||||
interface Direct extends Channel {
|
interface Direct
|
||||||
|
extends Channel {
|
||||||
/**
|
/**
|
||||||
* Request opening this channel from remote end.
|
* Request opening this channel from remote end.
|
||||||
*
|
*
|
||||||
@@ -57,19 +39,22 @@ public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
|||||||
* other connection-layer error
|
* other connection-layer error
|
||||||
* @throws TransportException error writing packets etc.
|
* @throws TransportException error writing packets etc.
|
||||||
*/
|
*/
|
||||||
void open() throws OpenFailException, ConnectionException, TransportException;
|
void open()
|
||||||
|
throws OpenFailException, ConnectionException, TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Forwarded channels are those that are initiated by the server. */
|
/** Forwarded channels are those that are initiated by the server. */
|
||||||
interface Forwarded extends Channel {
|
interface Forwarded
|
||||||
|
extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirm {@code CHANNEL_OPEN} request.
|
* Confirm {@code CHANNEL_OPEN} request.
|
||||||
*
|
*
|
||||||
* @throws TransportException error sending confirmation packet
|
* @throws TransportException error sending confirmation packet
|
||||||
*/
|
*/
|
||||||
void confirm() throws TransportException;
|
void confirm()
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
/** Returns the IP of where the forwarded connection originates. */
|
/** Returns the IP of where the forwarded connection originates. */
|
||||||
String getOriginatorIP();
|
String getOriginatorIP();
|
||||||
@@ -85,13 +70,15 @@ public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
|||||||
*
|
*
|
||||||
* @throws TransportException error sending rejection packet
|
* @throws TransportException error sending rejection packet
|
||||||
*/
|
*/
|
||||||
void reject(OpenFailException.Reason reason, String message) throws TransportException;
|
void reject(OpenFailException.Reason reason, String message)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Close this channel. */
|
/** Close this channel. */
|
||||||
void close() throws TransportException, ConnectionException;
|
void close()
|
||||||
|
throws TransportException, ConnectionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether auto-expansion of local window is set.
|
* Returns whether auto-expansion of local window is set.
|
||||||
@@ -103,38 +90,41 @@ public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
|||||||
/** Returns the channel ID */
|
/** Returns the channel ID */
|
||||||
int getID();
|
int getID();
|
||||||
|
|
||||||
/** Returns the {@code InputStream} for this channel. */
|
/** @return the {@code InputStream} for this channel. */
|
||||||
InputStream getInputStream();
|
InputStream getInputStream();
|
||||||
|
|
||||||
/** Returns the maximum packet size that we have specified. */
|
/** @return the maximum packet size that we have specified. */
|
||||||
int getLocalMaxPacketSize();
|
int getLocalMaxPacketSize();
|
||||||
|
|
||||||
/** Returns the current local window size. */
|
/** @return the current local window size. */
|
||||||
int getLocalWinSize();
|
int getLocalWinSize();
|
||||||
|
|
||||||
/** Returns an {@code OutputStream} for this channel. */
|
/** @return an {@code OutputStream} for this channel. */
|
||||||
OutputStream getOutputStream();
|
OutputStream getOutputStream();
|
||||||
|
|
||||||
/** Returns the channel ID at the remote end. */
|
/** @return the channel ID at the remote end. */
|
||||||
int getRecipient();
|
int getRecipient();
|
||||||
|
|
||||||
/** Returns the maximum packet size as specified by the remote end. */
|
/** @return the maximum packet size as specified by the remote end. */
|
||||||
int getRemoteMaxPacketSize();
|
int getRemoteMaxPacketSize();
|
||||||
|
|
||||||
/** Returns the current remote window size. */
|
/** @return the current remote window size. */
|
||||||
int getRemoteWinSize();
|
int getRemoteWinSize();
|
||||||
|
|
||||||
/** Returns the channel type identifier. */
|
/** @return the channel type identifier. */
|
||||||
String getType();
|
String getType();
|
||||||
|
|
||||||
/** Returns whether the channel is open. */
|
/** @return whether the channel is open. */
|
||||||
boolean isOpen();
|
boolean isOpen();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an EOF message to the server for this channel; indicating that no more data will be sent by us. The {@code
|
* Sends an EOF message to the server for this channel; indicating that no more data will be sent by us. The {@code
|
||||||
* OutputStream} for this channel will be closed and no longer usable.
|
* OutputStream} for this channel will be closed and no longer usable.
|
||||||
|
*
|
||||||
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
void sendEOF() throws TransportException;
|
void sendEOF()
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ import java.io.InterruptedIOException;
|
|||||||
* {@link InputStream} for channels. Can {@link #receive(byte[], int, int) receive} data into its buffer for serving to
|
* {@link InputStream} for channels. Can {@link #receive(byte[], int, int) receive} data into its buffer for serving to
|
||||||
* readers.
|
* readers.
|
||||||
*/
|
*/
|
||||||
public final class ChannelInputStream extends InputStream implements ErrorNotifiable {
|
public final class ChannelInputStream
|
||||||
|
extends InputStream
|
||||||
|
implements ErrorNotifiable {
|
||||||
|
|
||||||
private final Logger log;
|
private final Logger log;
|
||||||
|
|
||||||
@@ -104,14 +106,16 @@ public final class ChannelInputStream extends InputStream implements ErrorNotifi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read()
|
||||||
|
throws IOException {
|
||||||
synchronized (b) {
|
synchronized (b) {
|
||||||
return read(b, 0, 1) == -1 ? -1 : b[0];
|
return read(b, 0, 1) == -1 ? -1 : b[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] b, int off, int len) throws IOException {
|
public int read(byte[] b, int off, int len)
|
||||||
|
throws IOException {
|
||||||
synchronized (buf) {
|
synchronized (buf) {
|
||||||
for (; ;) {
|
for (; ;) {
|
||||||
if (buf.available() > 0)
|
if (buf.available() > 0)
|
||||||
@@ -140,7 +144,8 @@ public final class ChannelInputStream extends InputStream implements ErrorNotifi
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receive(byte[] data, int offset, int len) throws ConnectionException, TransportException {
|
public void receive(byte[] data, int offset, int len)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
if (eof)
|
if (eof)
|
||||||
throw new ConnectionException("Getting data on EOF'ed stream");
|
throw new ConnectionException("Getting data on EOF'ed stream");
|
||||||
synchronized (buf) {
|
synchronized (buf) {
|
||||||
@@ -152,12 +157,14 @@ public final class ChannelInputStream extends InputStream implements ErrorNotifi
|
|||||||
checkWindow();
|
checkWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkWindow() throws TransportException {
|
private void checkWindow()
|
||||||
|
throws TransportException {
|
||||||
synchronized (win) {
|
synchronized (win) {
|
||||||
final int adjustment = win.neededAdjustment();
|
final int adjustment = win.neededAdjustment();
|
||||||
if (adjustment > 0) {
|
if (adjustment > 0) {
|
||||||
log.info("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
log.info("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
||||||
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST).putInt(chan.getRecipient()).putInt(adjustment));
|
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
|
||||||
|
.putInt(chan.getRecipient()).putInt(adjustment));
|
||||||
win.expand(adjustment);
|
win.expand(adjustment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ import java.io.OutputStream;
|
|||||||
* {@link OutputStream} for channels. Buffers data upto the remote window's maximum packet size. Data can also be
|
* {@link OutputStream} for channels. Buffers data upto the remote window's maximum packet size. Data can also be
|
||||||
* flushed via {@link #flush()} and is also flushed on {@link #close()}.
|
* flushed via {@link #flush()} and is also flushed on {@link #close()}.
|
||||||
*/
|
*/
|
||||||
public final class ChannelOutputStream extends OutputStream implements ErrorNotifiable {
|
public final class ChannelOutputStream
|
||||||
|
extends OutputStream
|
||||||
|
implements ErrorNotifiable {
|
||||||
|
|
||||||
private final Channel chan;
|
private final Channel chan;
|
||||||
private Transport trans;
|
private Transport trans;
|
||||||
@@ -77,13 +79,15 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(int w) throws IOException {
|
public synchronized void write(int w)
|
||||||
|
throws IOException {
|
||||||
b[0] = (byte) w;
|
b[0] = (byte) w;
|
||||||
write(b, 0, 1);
|
write(b, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(byte[] data, int off, int len) throws IOException {
|
public synchronized void write(byte[] data, int off, int len)
|
||||||
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
|
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
|
||||||
@@ -102,7 +106,8 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
|||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void checkClose() throws SSHException {
|
private synchronized void checkClose()
|
||||||
|
throws SSHException {
|
||||||
if (closed)
|
if (closed)
|
||||||
if (error != null)
|
if (error != null)
|
||||||
throw error;
|
throw error;
|
||||||
@@ -111,7 +116,8 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public synchronized void close()
|
||||||
|
throws IOException {
|
||||||
if (!closed)
|
if (!closed)
|
||||||
try {
|
try {
|
||||||
flush();
|
flush();
|
||||||
@@ -126,7 +132,8 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void flush() throws IOException {
|
public synchronized void flush()
|
||||||
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
|
|
||||||
if (bufferLength <= 0) // No data to send
|
if (bufferLength <= 0) // No data to send
|
||||||
|
|||||||
@@ -12,35 +12,20 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
|
|
||||||
public class OpenFailException extends ConnectionException {
|
public class OpenFailException
|
||||||
|
extends ConnectionException {
|
||||||
|
|
||||||
public enum Reason {
|
public enum Reason {
|
||||||
UNKNOWN(0), ADMINISTRATIVELY_PROHIBITED(1), CONNECT_FAILED(2), UNKNOWN_CHANNEL_TYPE(3), RESOURCE_SHORTAGE(4);
|
UNKNOWN(0),
|
||||||
|
ADMINISTRATIVELY_PROHIBITED(1),
|
||||||
|
CONNECT_FAILED(2),
|
||||||
|
UNKNOWN_CHANNEL_TYPE(3),
|
||||||
|
RESOURCE_SHORTAGE(4);
|
||||||
|
|
||||||
public static Reason fromInt(int code) {
|
public static Reason fromInt(int code) {
|
||||||
for (Reason rc : Reason.values())
|
for (Reason rc : Reason.values())
|
||||||
|
|||||||
@@ -68,13 +68,15 @@ public abstract class Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Controls how much data we can send before an adjustment notification from remote end is required. */
|
/** Controls how much data we can send before an adjustment notification from remote end is required. */
|
||||||
public static final class Remote extends Window {
|
public static final class Remote
|
||||||
|
extends Window {
|
||||||
|
|
||||||
public Remote(int chanID, int initialWinSize, int maxPacketSize) {
|
public Remote(int chanID, int initialWinSize, int maxPacketSize) {
|
||||||
super(chanID, "remote win", initialWinSize, maxPacketSize);
|
super(chanID, "remote win", initialWinSize, maxPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitAndConsume(int howMuch) throws ConnectionException {
|
public void waitAndConsume(int howMuch)
|
||||||
|
throws ConnectionException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
while (size < howMuch) {
|
while (size < howMuch) {
|
||||||
log.debug("Waiting, need window space for {} bytes", howMuch);
|
log.debug("Waiting, need window space for {} bytes", howMuch);
|
||||||
@@ -91,7 +93,8 @@ public abstract class Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Controls how much data remote end can send before an adjustment notification from us is required. */
|
/** Controls how much data remote end can send before an adjustment notification from us is required. */
|
||||||
public static final class Local extends Window {
|
public static final class Local
|
||||||
|
extends Window {
|
||||||
|
|
||||||
private final int initialSize;
|
private final int initialSize;
|
||||||
private final int threshold;
|
private final int threshold;
|
||||||
@@ -102,7 +105,8 @@ public abstract class Window {
|
|||||||
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int neededAdjustment() throws TransportException {
|
public int neededAdjustment()
|
||||||
|
throws TransportException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
return (size - threshold <= 0) ? (initialSize - size) : 0;
|
return (size - threshold <= 0) ? (initialSize - size) : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ import net.schmizz.sshj.transport.TransportException;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Base class for direct channels whose open is initated by the client. */
|
/** Base class for direct channels whose open is initated by the client. */
|
||||||
public abstract class AbstractDirectChannel extends AbstractChannel implements Channel.Direct {
|
public abstract class AbstractDirectChannel
|
||||||
|
extends AbstractChannel
|
||||||
|
implements Channel.Direct {
|
||||||
|
|
||||||
protected AbstractDirectChannel(String name, Connection conn) {
|
protected AbstractDirectChannel(String name, Connection conn) {
|
||||||
super(name, conn);
|
super(name, conn);
|
||||||
@@ -58,7 +60,8 @@ public abstract class AbstractDirectChannel extends AbstractChannel implements C
|
|||||||
conn.attach(this);
|
conn.attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open() throws ConnectionException, TransportException {
|
public void open()
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
trans.write(buildOpenReq());
|
trans.write(buildOpenReq());
|
||||||
open.await(conn.getTimeout(), TimeUnit.SECONDS);
|
open.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,8 @@ public abstract class AbstractDirectChannel extends AbstractChannel implements C
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void gotUnknown(Message cmd, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void gotUnknown(Message cmd, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
|
||||||
case CHANNEL_OPEN_CONFIRMATION:
|
case CHANNEL_OPEN_CONFIRMATION:
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ import java.net.SocketAddress;
|
|||||||
|
|
||||||
public class LocalPortForwarder {
|
public class LocalPortForwarder {
|
||||||
|
|
||||||
private class DirectTCPIPChannel extends AbstractDirectChannel {
|
private class DirectTCPIPChannel
|
||||||
|
extends AbstractDirectChannel {
|
||||||
|
|
||||||
private final Socket sock;
|
private final Socket sock;
|
||||||
|
|
||||||
@@ -60,13 +61,15 @@ public class LocalPortForwarder {
|
|||||||
this.sock = sock;
|
this.sock = sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start() throws IOException {
|
private void start()
|
||||||
|
throws IOException {
|
||||||
sock.setSendBufferSize(getLocalMaxPacketSize());
|
sock.setSendBufferSize(getLocalMaxPacketSize());
|
||||||
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
|
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
|
||||||
|
|
||||||
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(this,
|
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(this,
|
||||||
new Closeable() {
|
new Closeable() {
|
||||||
public void close() throws IOException {
|
public void close()
|
||||||
|
throws IOException {
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -102,7 +105,8 @@ public class LocalPortForwarder {
|
|||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port) throws IOException {
|
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port)
|
||||||
|
throws IOException {
|
||||||
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
|
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +122,8 @@ public class LocalPortForwarder {
|
|||||||
*
|
*
|
||||||
* @throws IOException if there is an error binding on specified {@code listeningAddr}
|
* @throws IOException if there is an error binding on specified {@code listeningAddr}
|
||||||
*/
|
*/
|
||||||
public LocalPortForwarder(ServerSocketFactory ssf, Connection conn, SocketAddress listeningAddr, String host, int port) throws IOException {
|
public LocalPortForwarder(ServerSocketFactory ssf, Connection conn, SocketAddress listeningAddr, String host, int port)
|
||||||
|
throws IOException {
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
@@ -132,7 +137,8 @@ public class LocalPortForwarder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Start listening for incoming connections and forward to remote host as a channel. */
|
/** Start listening for incoming connections and forward to remote host as a channel. */
|
||||||
public void listen() throws IOException {
|
public void listen()
|
||||||
|
throws IOException {
|
||||||
log.info("Listening on {}", ss.getLocalSocketAddress());
|
log.info("Listening on {}", ss.getLocalSocketAddress());
|
||||||
Socket sock;
|
Socket sock;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@@ -56,10 +56,12 @@ import java.util.Map;
|
|||||||
* @see Shell
|
* @see Shell
|
||||||
* @see Subsystem
|
* @see Subsystem
|
||||||
*/
|
*/
|
||||||
public interface Session extends Channel {
|
public interface Session
|
||||||
|
extends Channel {
|
||||||
|
|
||||||
/** Command API. */
|
/** Command API. */
|
||||||
interface Command extends Channel {
|
interface Command
|
||||||
|
extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from the command's {@code stderr} stream into a string (blocking).
|
* Read from the command's {@code stderr} stream into a string (blocking).
|
||||||
@@ -68,7 +70,8 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws IOException if error reading from the stream
|
* @throws IOException if error reading from the stream
|
||||||
*/
|
*/
|
||||||
String getErrorAsString() throws IOException;
|
String getErrorAsString()
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/** Returns the command's {@code stderr} stream. */
|
/** Returns the command's {@code stderr} stream. */
|
||||||
InputStream getErrorStream();
|
InputStream getErrorStream();
|
||||||
@@ -105,7 +108,8 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws IOException if error reading from the stream
|
* @throws IOException if error reading from the stream
|
||||||
*/
|
*/
|
||||||
String getOutputAsString() throws IOException;
|
String getOutputAsString()
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a signal to the remote command.
|
* Send a signal to the remote command.
|
||||||
@@ -114,12 +118,14 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws TransportException if error sending the signal
|
* @throws TransportException if error sending the signal
|
||||||
*/
|
*/
|
||||||
void signal(Signal signal) throws TransportException;
|
void signal(Signal signal)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shell API. */
|
/** Shell API. */
|
||||||
interface Shell extends Channel {
|
interface Shell
|
||||||
|
extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the client can do local flow control using {@code control-S} and {@code control-Q}.
|
* Whether the client can do local flow control using {@code control-S} and {@code control-Q}.
|
||||||
@@ -139,7 +145,8 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
void changeWindowDimensions(int cols, int rows, int width, int height) throws TransportException;
|
void changeWindowDimensions(int cols, int rows, int width, int height)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
/** Returns the shell's {@code stderr} stream. */
|
/** Returns the shell's {@code stderr} stream. */
|
||||||
InputStream getErrorStream();
|
InputStream getErrorStream();
|
||||||
@@ -151,12 +158,14 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws TransportException if error sending the signal
|
* @throws TransportException if error sending the signal
|
||||||
*/
|
*/
|
||||||
void signal(Signal signal) throws TransportException;
|
void signal(Signal signal)
|
||||||
|
throws TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Subsystem API. */
|
/** Subsystem API. */
|
||||||
interface Subsystem extends Channel {
|
interface Subsystem
|
||||||
|
extends Channel {
|
||||||
Integer getExitStatus();
|
Integer getExitStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +176,8 @@ public interface Session extends Channel {
|
|||||||
*
|
*
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
void allocateDefaultPTY() throws ConnectionException, TransportException;
|
void allocateDefaultPTY()
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a psuedo-terminal for this session.
|
* Allocate a psuedo-terminal for this session.
|
||||||
@@ -197,7 +207,8 @@ public interface Session extends Channel {
|
|||||||
* @throws ConnectionException if the request to execute the command failed
|
* @throws ConnectionException if the request to execute the command failed
|
||||||
* @throws TransportException if there is an error sending the request
|
* @throws TransportException if there is an error sending the request
|
||||||
*/
|
*/
|
||||||
Command exec(String command) throws ConnectionException, TransportException;
|
Command exec(String command)
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request X11 forwarding.
|
* Request X11 forwarding.
|
||||||
@@ -209,7 +220,8 @@ public interface Session extends Channel {
|
|||||||
* @throws ConnectionException if the request failed
|
* @throws ConnectionException if the request failed
|
||||||
* @throws TransportException if there was an error sending the request
|
* @throws TransportException if there was an error sending the request
|
||||||
*/
|
*/
|
||||||
void reqX11Forwarding(String authProto, String authCookie, int screen) throws ConnectionException,
|
void reqX11Forwarding(String authProto, String authCookie, int screen)
|
||||||
|
throws ConnectionException,
|
||||||
TransportException;
|
TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -221,7 +233,8 @@ public interface Session extends Channel {
|
|||||||
* @throws ConnectionException if the request failed
|
* @throws ConnectionException if the request failed
|
||||||
* @throws TransportException if there was an error sending the request
|
* @throws TransportException if there was an error sending the request
|
||||||
*/
|
*/
|
||||||
void setEnvVar(String name, String value) throws ConnectionException, TransportException;
|
void setEnvVar(String name, String value)
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a shell.
|
* Request a shell.
|
||||||
@@ -231,7 +244,8 @@ public interface Session extends Channel {
|
|||||||
* @throws ConnectionException if the request failed
|
* @throws ConnectionException if the request failed
|
||||||
* @throws TransportException if there was an error sending the request
|
* @throws TransportException if there was an error sending the request
|
||||||
*/
|
*/
|
||||||
Shell startShell() throws ConnectionException, TransportException;
|
Shell startShell()
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a subsystem.
|
* Request a subsystem.
|
||||||
@@ -243,6 +257,7 @@ public interface Session extends Channel {
|
|||||||
* @throws ConnectionException if the request failed
|
* @throws ConnectionException if the request failed
|
||||||
* @throws TransportException if there was an error sending the request
|
* @throws TransportException if there was an error sending the request
|
||||||
*/
|
*/
|
||||||
Subsystem startSubsystem(String name) throws ConnectionException, TransportException;
|
Subsystem startSubsystem(String name)
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
/** {@link Session} implementation. */
|
/** {@link Session} implementation. */
|
||||||
public class
|
public class
|
||||||
SessionChannel extends AbstractDirectChannel implements Session, Session.Command, Session.Shell,
|
SessionChannel
|
||||||
Session.Subsystem {
|
extends AbstractDirectChannel
|
||||||
|
implements Session, Session.Command, Session.Shell, Session.Subsystem {
|
||||||
|
|
||||||
private Integer exitStatus;
|
private Integer exitStatus;
|
||||||
|
|
||||||
@@ -69,7 +70,8 @@ public class
|
|||||||
super("session", conn);
|
super("session", conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void allocateDefaultPTY() throws ConnectionException, TransportException {
|
public void allocateDefaultPTY()
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
// TODO FIXME (maybe?): These modes were originally copied from what SSHD was doing;
|
// TODO FIXME (maybe?): These modes were originally copied from what SSHD was doing;
|
||||||
// and then the echo modes were set to 0 to better serve the PTY example.
|
// and then the echo modes were set to 0 to better serve the PTY example.
|
||||||
// Not sure what default PTY modes should be.
|
// Not sure what default PTY modes should be.
|
||||||
@@ -103,7 +105,8 @@ public class
|
|||||||
return canDoFlowControl;
|
return canDoFlowControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void changeWindowDimensions(int cols, int rows, int width, int height) throws TransportException {
|
public void changeWindowDimensions(int cols, int rows, int width, int height)
|
||||||
|
throws TransportException {
|
||||||
sendChannelRequest(
|
sendChannelRequest(
|
||||||
"pty-req",
|
"pty-req",
|
||||||
false,
|
false,
|
||||||
@@ -115,13 +118,16 @@ public class
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command exec(String command) throws ConnectionException, TransportException {
|
public Command exec(String command)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
log.info("Will request to exec `{}`", command);
|
log.info("Will request to exec `{}`", command);
|
||||||
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command)).await(conn.getTimeout(), TimeUnit.SECONDS);
|
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
||||||
|
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getErrorAsString() throws IOException {
|
public String getErrorAsString()
|
||||||
|
throws IOException {
|
||||||
return StreamCopier.copyStreamToString(err);
|
return StreamCopier.copyStreamToString(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,12 +147,14 @@ public class
|
|||||||
return exitStatus;
|
return exitStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOutputAsString() throws IOException {
|
public String getOutputAsString()
|
||||||
|
throws IOException {
|
||||||
return StreamCopier.copyStreamToString(getInputStream());
|
return StreamCopier.copyStreamToString(getInputStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleRequest(String req, SSHPacket buf) throws ConnectionException, TransportException {
|
public void handleRequest(String req, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
if ("xon-xoff".equals(req))
|
if ("xon-xoff".equals(req))
|
||||||
canDoFlowControl = buf.readBoolean();
|
canDoFlowControl = buf.readBoolean();
|
||||||
else if ("exit-status".equals(req))
|
else if ("exit-status".equals(req))
|
||||||
@@ -160,7 +168,8 @@ public class
|
|||||||
super.handleRequest(req, buf);
|
super.handleRequest(req, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reqX11Forwarding(String authProto, String authCookie, int screen) throws ConnectionException,
|
public void reqX11Forwarding(String authProto, String authCookie, int screen)
|
||||||
|
throws ConnectionException,
|
||||||
TransportException {
|
TransportException {
|
||||||
sendChannelRequest(
|
sendChannelRequest(
|
||||||
"x11-req",
|
"x11-req",
|
||||||
@@ -173,22 +182,28 @@ public class
|
|||||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnvVar(String name, String value) throws ConnectionException, TransportException {
|
public void setEnvVar(String name, String value)
|
||||||
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value)).await(conn.getTimeout(), TimeUnit.SECONDS);
|
throws ConnectionException, TransportException {
|
||||||
|
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
||||||
|
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void signal(Signal sig) throws TransportException {
|
public void signal(Signal sig)
|
||||||
|
throws TransportException {
|
||||||
sendChannelRequest("signal", false, new Buffer.PlainBuffer().putString(sig.toString()));
|
sendChannelRequest("signal", false, new Buffer.PlainBuffer().putString(sig.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Shell startShell() throws ConnectionException, TransportException {
|
public Shell startShell()
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
|
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Subsystem startSubsystem(String name) throws ConnectionException, TransportException {
|
public Subsystem startSubsystem(String name)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
log.info("Will request `{}` subsystem", name);
|
log.info("Will request `{}` subsystem", name);
|
||||||
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name)).await(conn.getTimeout(), TimeUnit.SECONDS);
|
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
||||||
|
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +224,8 @@ public class
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void gotExtendedData(int dataTypeCode, SSHPacket buf) throws ConnectionException, TransportException {
|
protected void gotExtendedData(int dataTypeCode, SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
if (dataTypeCode == 1)
|
if (dataTypeCode == 1)
|
||||||
receiveInto(err, buf);
|
receiveInto(err, buf);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public interface SessionFactory {
|
|||||||
* @throws SSHException
|
* @throws SSHException
|
||||||
* @see {@link Session}
|
* @see {@link Session}
|
||||||
*/
|
*/
|
||||||
Session startSession() throws SSHException;
|
Session startSession()
|
||||||
|
throws SSHException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,21 @@ package net.schmizz.sshj.connection.channel.direct;
|
|||||||
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
||||||
public enum Signal {
|
public enum Signal {
|
||||||
|
|
||||||
ABRT("ABRT"), ALRM("ALRM"), FPE("FPE"), HUP("HUP"), ILL("ILL"), INT("INT"), KILL("KILL"), PIPE("PIPE"), QUIT(
|
ABRT("ABRT"),
|
||||||
"QUIT"), SEGV("SEGV"), TERM("TERM"), USR1("USR1"), USR2("USR2"), UNKNOWN("UNKNOWN");
|
ALRM("ALRM"),
|
||||||
|
FPE("FPE"),
|
||||||
|
HUP("HUP"),
|
||||||
|
ILL("ILL"),
|
||||||
|
INT("INT"),
|
||||||
|
KILL("KILL"),
|
||||||
|
PIPE("PIPE"),
|
||||||
|
QUIT(
|
||||||
|
"QUIT"),
|
||||||
|
SEGV("SEGV"),
|
||||||
|
TERM("TERM"),
|
||||||
|
USR1("USR1"),
|
||||||
|
USR2("USR2"),
|
||||||
|
UNKNOWN("UNKNOWN");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create from the string representation used when the signal is received as part of an SSH packet.
|
* Create from the string representation used when the signal is received as part of an SSH packet.
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ import net.schmizz.sshj.connection.channel.OpenFailException.Reason;
|
|||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
/** Base class for forwarded channels whose open is initiated by the server. */
|
/** Base class for forwarded channels whose open is initiated by the server. */
|
||||||
public abstract class AbstractForwardedChannel extends AbstractChannel implements Channel.Forwarded {
|
public abstract class AbstractForwardedChannel
|
||||||
|
extends AbstractChannel
|
||||||
|
implements Channel.Forwarded {
|
||||||
|
|
||||||
protected final String origIP;
|
protected final String origIP;
|
||||||
protected final int origPort;
|
protected final int origPort;
|
||||||
@@ -60,7 +62,8 @@ public abstract class AbstractForwardedChannel extends AbstractChannel implement
|
|||||||
init(recipient, remoteWinSize, remoteMaxPacketSize);
|
init(recipient, remoteWinSize, remoteMaxPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void confirm() throws TransportException {
|
public void confirm()
|
||||||
|
throws TransportException {
|
||||||
log.info("Confirming `{}` channel #{}", getType(), getID());
|
log.info("Confirming `{}` channel #{}", getType(), getID());
|
||||||
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
||||||
conn.attach(this);
|
conn.attach(this);
|
||||||
@@ -71,7 +74,8 @@ public abstract class AbstractForwardedChannel extends AbstractChannel implement
|
|||||||
open.set();
|
open.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reject(Reason reason, String message) throws TransportException {
|
public void reject(Reason reason, String message)
|
||||||
|
throws TransportException {
|
||||||
log.info("Rejecting `{}` channel: {}", getType(), message);
|
log.info("Rejecting `{}` channel: {}", getType(), message);
|
||||||
conn.sendOpenFailure(getRecipient(), reason, message);
|
conn.sendOpenFailure(getRecipient(), reason, message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
@@ -47,7 +27,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/** Base class for {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener}'s. */
|
/** Base class for {@link net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener}'s. */
|
||||||
public abstract class AbstractForwardedChannelOpener implements ForwardedChannelOpener {
|
public abstract class AbstractForwardedChannelOpener
|
||||||
|
implements ForwardedChannelOpener {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,14 @@ public interface ConnectListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify this listener of a new forwarded channel. An implementation should firstly {@link
|
* Notify this listener of a new forwarded channel. An implementation should firstly {@link
|
||||||
* net.schmizz.sshj.connection.channel.Channel.Forwarded#confirm() confirm} or {@link
|
* Channel.Forwarded#confirm() confirm} or {@link Channel.Forwarded#reject(net.schmizz.sshj.connection.channel.OpenFailException.Reason,
|
||||||
* net.schmizz.sshj.connection.channel.Channel.Forwarded#reject() reject} that channel.
|
* String)} reject} that channel.
|
||||||
*
|
*
|
||||||
* @param chan the {@link net.schmizz.sshj.connection.channel.Channel.Forwarded forwarded channel}
|
* @param chan the {@link net.schmizz.sshj.connection.channel.Channel.Forwarded forwarded channel}
|
||||||
*
|
*
|
||||||
* @throws java.io.IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
void gotConnect(Channel.Forwarded chan) throws IOException;
|
void gotConnect(Channel.Forwarded chan)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public interface ForwardedChannelOpener {
|
|||||||
* @param buf {@link net.schmizz.sshj.common.SSHPacket} containg the request except for the message identifier and
|
* @param buf {@link net.schmizz.sshj.common.SSHPacket} containg the request except for the message identifier and
|
||||||
* channel type field
|
* channel type field
|
||||||
*/
|
*/
|
||||||
void handleOpen(SSHPacket buf) throws ConnectionException, TransportException;
|
void handleOpen(SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
|
|
||||||
@@ -48,7 +28,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Handles remote port forwarding. */
|
/** Handles remote port forwarding. */
|
||||||
public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
public class RemotePortForwarder
|
||||||
|
extends AbstractForwardedChannelOpener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a particular forwarding. From RFC 4254, s. 7.1
|
* Represents a particular forwarding. From RFC 4254, s. 7.1
|
||||||
@@ -139,14 +120,16 @@ public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A {@code forwarded-tcpip} channel. */
|
/** A {@code forwarded-tcpip} channel. */
|
||||||
public static class ForwardedTCPIPChannel extends AbstractForwardedChannel {
|
public static class ForwardedTCPIPChannel
|
||||||
|
extends AbstractForwardedChannel {
|
||||||
|
|
||||||
public static final String TYPE = "forwarded-tcpip";
|
public static final String TYPE = "forwarded-tcpip";
|
||||||
|
|
||||||
private final Forward fwd;
|
private final Forward fwd;
|
||||||
|
|
||||||
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
|
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
|
||||||
Forward fwd, String origIP, int origPort) throws TransportException {
|
Forward fwd, String origIP, int origPort)
|
||||||
|
throws TransportException {
|
||||||
super(TYPE, conn, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
super(TYPE, conn, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||||
this.fwd = fwd;
|
this.fwd = fwd;
|
||||||
}
|
}
|
||||||
@@ -182,7 +165,8 @@ public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
|||||||
* @throws ConnectionException if there is an error requesting the forwarding
|
* @throws ConnectionException if there is an error requesting the forwarding
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
public Forward bind(Forward forward, ConnectListener listener) throws ConnectionException, TransportException {
|
public Forward bind(Forward forward, ConnectListener listener)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
SSHPacket reply = req(PF_REQ, forward);
|
SSHPacket reply = req(PF_REQ, forward);
|
||||||
if (forward.port == 0)
|
if (forward.port == 0)
|
||||||
forward.port = reply.readInt();
|
forward.port = reply.readInt();
|
||||||
@@ -199,7 +183,8 @@ public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
|||||||
* @throws ConnectionException if there is an error with the cancellation request
|
* @throws ConnectionException if there is an error with the cancellation request
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
*/
|
*/
|
||||||
public void cancel(Forward forward) throws ConnectionException, TransportException {
|
public void cancel(Forward forward)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
try {
|
try {
|
||||||
req(PF_CANCEL, forward);
|
req(PF_CANCEL, forward);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -207,8 +192,10 @@ public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SSHPacket req(String reqName, Forward forward) throws ConnectionException, TransportException {
|
protected SSHPacket req(String reqName, Forward forward)
|
||||||
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putInt(forward.port).getCompactData();
|
throws ConnectionException, TransportException {
|
||||||
|
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putInt(forward.port)
|
||||||
|
.getCompactData();
|
||||||
return conn.sendGlobalRequest(reqName, true, specifics)
|
return conn.sendGlobalRequest(reqName, true, specifics)
|
||||||
.get(conn.getTimeout(), TimeUnit.SECONDS);
|
.get(conn.getTimeout(), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
@@ -222,7 +209,8 @@ public class RemotePortForwarder extends AbstractForwardedChannelOpener {
|
|||||||
* Internal API. Creates a {@link ForwardedTCPIPChannel} from the {@code CHANNEL_OPEN} request and calls associated
|
* Internal API. Creates a {@link ForwardedTCPIPChannel} from the {@code CHANNEL_OPEN} request and calls associated
|
||||||
* {@code ConnectListener} for that forward in a separate thread.
|
* {@code ConnectListener} for that forward in a separate thread.
|
||||||
*/
|
*/
|
||||||
public void handleOpen(SSHPacket buf) throws ConnectionException, TransportException {
|
public void handleOpen(SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
final ForwardedTCPIPChannel chan = new ForwardedTCPIPChannel(conn, buf.readInt(), buf.readInt(), buf.readInt(),
|
final ForwardedTCPIPChannel chan = new ForwardedTCPIPChannel(conn, buf.readInt(), buf.readInt(), buf.readInt(),
|
||||||
new Forward(buf.readString(), buf.readInt()),
|
new Forward(buf.readString(), buf.readInt()),
|
||||||
buf.readString(), buf.readInt());
|
buf.readString(), buf.readInt());
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ import java.net.SocketAddress;
|
|||||||
* A {@link net.schmizz.sshj.connection.channel.forwarded.ConnectListener} that forwards what is received over the
|
* A {@link net.schmizz.sshj.connection.channel.forwarded.ConnectListener} that forwards what is received over the
|
||||||
* channel to a socket and vice-versa.
|
* channel to a socket and vice-versa.
|
||||||
*/
|
*/
|
||||||
public class SocketForwardingConnectListener implements ConnectListener {
|
public class SocketForwardingConnectListener
|
||||||
|
implements ConnectListener {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@@ -42,7 +43,8 @@ public class SocketForwardingConnectListener implements ConnectListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** On connect, confirm the channel and start forwarding. */
|
/** On connect, confirm the channel and start forwarding. */
|
||||||
public void gotConnect(Channel.Forwarded chan) throws IOException {
|
public void gotConnect(Channel.Forwarded chan)
|
||||||
|
throws IOException {
|
||||||
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
|
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
|
||||||
|
|
||||||
final Socket sock = new Socket();
|
final Socket sock = new Socket();
|
||||||
@@ -55,7 +57,8 @@ public class SocketForwardingConnectListener implements ConnectListener {
|
|||||||
chan.confirm();
|
chan.confirm();
|
||||||
|
|
||||||
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(chan, new Closeable() {
|
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(chan, new Closeable() {
|
||||||
public void close() throws IOException {
|
public void close()
|
||||||
|
throws IOException {
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ import net.schmizz.sshj.transport.TransportException;
|
|||||||
* Handles forwarded {@code x11} channels. The actual request to forward X11 should be made from the specific {@link
|
* Handles forwarded {@code x11} channels. The actual request to forward X11 should be made from the specific {@link
|
||||||
* net.schmizz.sshj.connection.channel.direct.Session}.
|
* net.schmizz.sshj.connection.channel.direct.Session}.
|
||||||
*/
|
*/
|
||||||
public class X11Forwarder extends AbstractForwardedChannelOpener {
|
public class X11Forwarder
|
||||||
|
extends AbstractForwardedChannelOpener {
|
||||||
|
|
||||||
/** An {@code x11} forwarded channel. */
|
/** An {@code x11} forwarded channel. */
|
||||||
public static class X11Channel extends AbstractForwardedChannel {
|
public static class X11Channel
|
||||||
|
extends AbstractForwardedChannel {
|
||||||
|
|
||||||
public static final String TYPE = "x11";
|
public static final String TYPE = "x11";
|
||||||
|
|
||||||
@@ -52,7 +54,8 @@ public class X11Forwarder extends AbstractForwardedChannelOpener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Internal API */
|
/** Internal API */
|
||||||
public void handleOpen(SSHPacket buf) throws ConnectionException, TransportException {
|
public void handleOpen(SSHPacket buf)
|
||||||
|
throws ConnectionException, TransportException {
|
||||||
callListener(listener, new X11Channel(conn, buf.readInt(), buf.readInt(), buf.readInt(), buf.readString(), buf
|
callListener(listener, new X11Channel(conn, buf.readInt(), buf.readInt(), buf.readInt(), buf.readString(), buf
|
||||||
.readInt()));
|
.readInt()));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user