Compare commits

...

56 Commits

Author SHA1 Message Date
Shikhar Bhushan
20c5ab8dfc [maven-release-plugin] prepare release v0.3.1 2011-03-02 20:44:25 +00:00
Incendium
d9c438ed16 Fixed issue with StatefulSFTPClient.put not transferring files. 2011-03-01 14:53:12 -08:00
Shikhar Bhushan
653e8ad4f2 In SCP, warning means error... 2011-02-27 20:48:26 +00:00
Shikhar Bhushan
c46dc913e8 A Config suitable for running with Android 2.3+ 2011-02-12 23:25:32 +00:00
Shikhar Bhushan
069ebbd47d Try and be helpful on SessionChannel reuse with a more explicit error condition 2011-02-12 20:25:26 +00:00
Shikhar Bhushan
da2cec8fa2 Add a timed join() method to Channel, update Exec example 2011-02-12 20:23:58 +00:00
Shikhar Bhushan
75caa8bcf3 Need to fix my intellij setup on linux... 2010-12-30 22:48:09 +00:00
Shikhar Bhushan
f664b7b24f Merge branch 'master' of github.com:shikhar/sshj 2010-12-30 22:43:34 +00:00
shikhar
70f3aeee68 SessionChannel should override notifyError() in order to notify the stderr stream 2010-12-30 22:43:00 +00:00
shikhar
882d40a1b6 SessionChannel should override notifyError() in order to notify the stderr stream 2010-12-30 22:38:02 +00:00
Shikhar Bhushan
9649b2f72e lets try this flattr thing 2010-08-22 00:09:04 +01:00
Shikhar Bhushan
79a8d0b3ad [maven-release-plugin] prepare for next development iteration 2010-08-15 19:39:01 +01:00
Shikhar Bhushan
2e7fcfd308 [maven-release-plugin] prepare release v0.3.0 2010-08-15 19:38:43 +01:00
Shikhar Bhushan
946422112d can only help 2010-08-15 19:01:57 +01:00
Shikhar Bhushan
b11f0be894 update readme 2010-08-14 00:34:38 +01:00
Shikhar Bhushan
ba6e5292c8 update readme: 2010-08-14 00:32:35 +01:00
Shikhar Bhushan
c8de9ed915 add Channel.join() 2010-08-13 23:01:35 +01:00
Shikhar Bhushan
7ccd078e52 deps update 2010-08-12 23:41:43 +01:00
Shikhar Bhushan
0aa8d5e141 . 2010-08-12 17:34:49 +01:00
Shikhar Bhushan
2e32bb9aca simplify 2010-08-12 17:31:42 +01:00
Shikhar Bhushan
2f4fa62b14 simplify 2010-08-12 17:22:35 +01:00
Shikhar Bhushan
8a4367cc7a minor doc update 2010-08-12 17:19:28 +01:00
Shikhar Bhushan
168272ad3b simplify DisconnectReason enum 2010-08-10 00:30:59 +01:00
Shikhar Bhushan
17eb5cff0f consolidate bitmask logic and fix subtle bug... 2010-08-08 17:55:30 +01:00
Shikhar Bhushan
ebd5036d64 enum reverse cache objects 2010-08-08 17:45:48 +01:00
Shikhar Bhushan
7797d774ac fixing up hostbased auth 2010-08-07 22:35:38 +01:00
Shikhar Bhushan
888a8f60d7 ws 2010-08-07 22:34:09 +01:00
Shikhar Bhushan
974e88efb4 no need to actually have API client specify sftp protocol version, so long as all versions < MAX_SUPPORTED_VERSIONS are supported. which is true for now! 2010-08-06 22:29:43 +01:00
Shikhar Bhushan
9a4a24737f incorrect sftp version compatibility check 2010-08-06 22:15:42 +01:00
Shikhar Bhushan
a1d17982ae public -> protected 2010-08-06 22:10:35 +01:00
Shikhar Bhushan
3beee8350d support sftp versions < 3 2010-08-06 00:02:21 +01:00
Shikhar Bhushan
3cd446b462 dumb 2010-08-06 00:01:51 +01:00
Shikhar Bhushan
486dbf2b05 unused var 2010-08-01 18:34:04 +01:00
Shikhar Bhushan
3cb235bbfd cleanup in transport.Heartbeater 2010-08-01 18:32:06 +01:00
Shikhar Bhushan
2882129211 reduce reliance on implicit channel close; add close() method to SFTP classes; update examples 2010-07-28 23:53:26 +01:00
Shikhar Bhushan
fb97ccb67c in ConnectionImpl#notifyDisconnect() -- why try to close channels politely, they should just be discarded 2010-07-20 23:48:05 +01:00
Shikhar Bhushan
8b21eff1d2 userauth failure log as debug and not error -- if it leads to error it will be raised as an exception anyway 2010-07-20 23:43:48 +01:00
Shikhar Bhushan
7874e7dbfd always use class name for making Loggers 2010-07-20 23:39:51 +01:00
Shikhar Bhushan
efc7702195 one log message is enough 2010-06-29 22:23:24 +01:00
Shikhar Bhushan
34a7b8e065 fixing the fix, just wow... 2010-06-25 22:09:51 +01:00
Shikhar Bhushan
50c42b97a3 sp 2010-06-18 23:10:05 +01:00
Shikhar Bhushan
826660ab3f narrow down error condition: more data is ok, underflow is not 2010-06-17 18:55:53 +01:00
Shikhar Bhushan
a3b6fde44a useless params, useless check, overkill... 2010-06-16 23:52:24 +01:00
Shikhar Bhushan
69555e9c74 update client version ident 2010-06-16 23:18:06 +01:00
Shikhar Bhushan
241f61bdd1 shdve been 0.3.0-SNAPSHOT 2010-06-13 14:35:09 +01:00
Shikhar Bhushan
0051dd420c [maven-release-plugin] prepare for next development iteration 2010-06-13 14:28:34 +01:00
Shikhar Bhushan
f2abc4b397 [maven-release-plugin] prepare release v0.2.3 2010-06-13 14:28:27 +01:00
Shikhar Bhushan
fe0d42fc97 [maven-release-plugin] prepare for next development iteration 2010-06-13 13:58:59 +01:00
Shikhar Bhushan
19e4670c24 [maven-release-plugin] prepare release v0.2.2 2010-06-13 13:58:51 +01:00
Shikhar Bhushan
fbd6e00720 [maven-release-plugin] prepare for next development iteration 2010-06-13 00:11:53 +01:00
Shikhar Bhushan
f69cdb1505 [maven-release-plugin] prepare release v0.2.1 2010-06-13 00:11:42 +01:00
Shikhar Bhushan
135b1c819b dep update 2010-06-13 00:09:11 +01:00
Shikhar Bhushan
9c51b862cd can't throw exception, shit fails on windows 2010-06-12 23:10:47 +01:00
Shikhar Bhushan
a6353cbb2d 2010-05-31 16:24:17 -07:00
Shikhar Bhushan
f11055a726 java 1.6 is a dep 2010-06-01 00:20:38 +01:00
Shikhar Bhushan
da98153ab6 [maven-release-plugin] prepare for next development iteration 2010-05-31 00:02:39 +01:00
45 changed files with 408 additions and 346 deletions

View File

@@ -1,3 +1,8 @@
.. image:: http://api.flattr.com/button/button-compact-static-100x17.png
:align: right
:alt: Flattr this
:target: http://flattr.com/thing/49085/sshj-ssh-scp-and-sftp-library-for-java
sshj - SSHv2 library for Java
==============================
@@ -6,10 +11,10 @@ To get started, have a look at one of the examples. Hopefully you will find the
Features of the library include:
* reading known_hosts files for host key verification
* password and publickey authentication
* publickey, password and keyboard-interactive authentication
* command, subsystem and shell channels
* local and remote port forwarding
* scp + complete sftp version 3 implementation
* scp + complete sftp version 0-3 implementation
Implementations of the following algorithms are included:
@@ -37,8 +42,7 @@ If you need something that is not implemented, it shouldn't be too hard to add (
Dependencies
-------------
slf4j_ is required. bouncycastle_ is highly recommended and required for using some of the crypto algorithms.
jzlib_ is required for using zlib compression.
Java 6+. slf4j_ is required. bouncycastle_ is highly recommended and required for using some of the crypto algorithms. jzlib_ is required for using zlib compression.
Help and discussion
@@ -53,8 +57,6 @@ Contributing
Fork away!
.. _buildr: http://buildr.apache.org/installing.html
.. _slf4j: http://www.slf4j.org/download.html
.. _bouncycastle: http://www.bouncycastle.org/java.html

18
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>jar</packaging>
<version>0.2.0</version>
<version>0.3.1</version>
<name>sshj</name>
<description>SSHv2 library for Java</description>
@@ -37,11 +37,11 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.11</version>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
<scope>provided</scope>
</dependency>
@@ -66,13 +66,13 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.20</version>
<version>0.9.24</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.20</version>
<version>0.9.24</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -111,7 +111,7 @@
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-4</version>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/assemble/examples.xml</descriptor>
@@ -176,7 +176,7 @@
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
</dependency>
<dependency>
@@ -187,12 +187,12 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.20</version>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.20</version>
<version>0.9.24</version>
</dependency>
</dependencies>
</profile>

View File

@@ -16,27 +16,32 @@
package examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/** This examples demonstrates how a remote command can be executed. */
public class Exec {
public static void main(String... args)
throws IOException {
SSHClient ssh = new SSHClient();
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
Command cmd = ssh.startSession().exec("ping -c 1 google.com");
System.out.print(cmd.getOutputAsString());
System.out.println("\n** exit status: " + cmd.getExitStatus());
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("ping -c 1 google.com");
System.out.print(cmd.getOutputAsString());
cmd.join(5, TimeUnit.SECONDS);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} finally {
session.close();
}
} finally {
ssh.disconnect();

View File

@@ -37,35 +37,35 @@ class RudimentaryPTY {
ssh.addHostKeyVerifier(new ConsoleKnownHostsVerifier(khFile, System.console()));
ssh.connect("localhost");
Shell shell = null;
try {
ssh.authPublickey(System.getProperty("user.name"));
final Session session = ssh.startSession();
session.allocateDefaultPTY();
try {
shell = session.startShell();
session.allocateDefaultPTY();
new StreamCopier("stdout", shell.getInputStream(), System.out)
.bufSize(shell.getLocalMaxPacketSize())
.start();
final Shell shell = session.startShell();
new StreamCopier("stderr", shell.getErrorStream(), System.err)
.bufSize(shell.getLocalMaxPacketSize())
.start();
new StreamCopier("stdout", shell.getInputStream(), System.out)
.bufSize(shell.getLocalMaxPacketSize())
.start();
// Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
// This is kinda messy because java only allows console input after you hit return
// But this is just an example... a GUI app could implement a proper PTY
StreamCopier.copy(System.in, shell.getOutputStream(), shell.getRemoteMaxPacketSize(), true);
new StreamCopier("stderr", shell.getErrorStream(), System.err)
.bufSize(shell.getLocalMaxPacketSize())
.start();
// Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
// This is kinda messy because java only allows console input after you hit return
// But this is just an example... a GUI app could implement a proper PTY
StreamCopier.copy(System.in, shell.getOutputStream(), shell.getRemoteMaxPacketSize(), true);
} finally {
session.close();
}
} finally {
if (shell != null)
shell.close();
ssh.disconnect();
}
}

View File

@@ -16,6 +16,7 @@
package examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import java.io.IOException;
@@ -24,14 +25,19 @@ public class SFTPDownload {
public static void main(String[] args)
throws IOException {
SSHClient ssh = new SSHClient();
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
final String src = "test_file";
final String target = "/tmp/";
ssh.newSFTPClient().get(src, target);
final SFTPClient sftp = ssh.newSFTPClient();
try {
sftp.get(src, target);
} finally {
sftp.close();
}
} finally {
ssh.disconnect();
}

View File

@@ -16,6 +16,7 @@
package examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import java.io.File;
import java.io.IOException;
@@ -25,14 +26,19 @@ public class SFTPUpload {
public static void main(String[] args)
throws IOException {
SSHClient ssh = new SSHClient();
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
final String src = System.getProperty("user.home") + File.separator + "test_file";
final String target = "/tmp/";
ssh.newSFTPClient().put(src, target);
final SFTPClient sftp = ssh.newSFTPClient();
try {
sftp.put(src, target);
} finally {
sftp.close();
}
} finally {
ssh.disconnect();
}

View File

@@ -29,7 +29,7 @@ public class X11 {
public static void main(String... args)
throws IOException, InterruptedException {
SSHClient ssh = new SSHClient();
final SSHClient ssh = new SSHClient();
// Compression makes X11 more feasible over slower connections
// ssh.useCompression();
@@ -55,7 +55,7 @@ public class X11 {
*/
sess.reqX11Forwarding("MIT-MAGIC-COOKIE-1", "b0956167c9ad8f34c8a2788878307dc9", 0);
Command cmd = sess.exec("/usr/X11/bin/xcalc");
final Command cmd = sess.exec("/usr/X11/bin/xcalc");
new StreamCopier("stdout", cmd.getInputStream(), System.out).start();
new StreamCopier("stderr", cmd.getErrorStream(), System.err).start();

View File

@@ -32,8 +32,9 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public class Future<V, T extends Throwable> {
private final Logger log;
private final Logger log = LoggerFactory.getLogger(getClass());
private final String name;
private final ExceptionChainer<T> chainer;
private final ReentrantLock lock;
private final Condition cond;
@@ -60,7 +61,7 @@ public class Future<V, T extends Throwable> {
* @param lock lock to use
*/
public Future(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
this.log = LoggerFactory.getLogger("<< " + name + " >>");
this.name = name;
this.chainer = chainer;
this.lock = lock == null ? new ReentrantLock() : lock;
this.cond = this.lock.newCondition();
@@ -74,7 +75,7 @@ public class Future<V, T extends Throwable> {
public void set(V val) {
lock();
try {
log.debug("Setting to `{}`", val);
log.debug("Setting <<{}>> to `{}`", name, val);
this.val = val;
cond.signalAll();
} finally {
@@ -139,14 +140,14 @@ public class Future<V, T extends Throwable> {
throw pendingEx;
if (val != null)
return val;
log.debug("Awaiting");
log.debug("Awaiting <<{}>>", name);
while (val == null && pendingEx == null)
if (timeout == 0)
cond.await();
else if (!cond.await(timeout, unit))
throw chainer.chain(new TimeoutException("Timeout expired"));
if (pendingEx != null) {
log.error("Woke to: {}", pendingEx.toString());
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
throw pendingEx;
}
return val;

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2010 Shikhar Bhushan
*
* Licensed 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;
import net.schmizz.sshj.transport.random.JCERandom;
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
public class AndroidConfig extends DefaultConfig {
@Override
protected void initRandomFactory(boolean ignored) {
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));
}
}

View File

@@ -91,7 +91,7 @@ public class DefaultConfig
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String VERSION = "SSHJ_0_1";
private static final String VERSION = "SSHJ_0_3";
public DefaultConfig() {
setVersion(VERSION);
@@ -134,6 +134,7 @@ public class DefaultConfig
new TripleDESCBC.Factory(),
new BlowfishCBC.Factory()));
boolean warn = false;
// Ref. https://issues.apache.org/jira/browse/SSHD-24
// "AES256 and AES192 requires unlimited cryptography extension"
for (Iterator<Factory.Named<Cipher>> i = avail.iterator(); i.hasNext();) {
@@ -144,10 +145,12 @@ public class DefaultConfig
final byte[] iv = new byte[c.getIVSize()];
c.init(Cipher.Mode.Encrypt, key, iv);
} catch (Exception e) {
log.warn("Disabling cipher `{}`: cipher strengths apparently limited by JCE policy", f.getName());
warn = true;
i.remove();
}
}
if (warn)
log.warn("Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy");
setCipherFactories(avail);
}

View File

@@ -33,6 +33,7 @@ import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward
import net.schmizz.sshj.connection.channel.forwarded.X11Forwarder;
import net.schmizz.sshj.connection.channel.forwarded.X11Forwarder.X11Channel;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.sftp.SFTPEngine;
import net.schmizz.sshj.sftp.StatefulSFTPClient;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
@@ -94,13 +95,15 @@ import java.util.List;
* client = new SSHClient();
* client.initUserKnownHosts();
* client.connect(&quot;hostname&quot;);
* try
* {
* try {
* client.authPassword(&quot;username&quot;, &quot;password&quot;);
* client.startSession().exec(&quot;true&quot;);
* client.getConnection().join();
* } finally
* {
* final Session session = client.startSession();
* try {
* session.exec(&quot;true&quot;);
* client.getConnection().join();
* } finally {
* session.close();
* } finally {
* client.disconnect();
* }
* </pre>
@@ -118,7 +121,6 @@ public class SSHClient
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
/** Transport layer */
protected final Transport trans;
@@ -156,20 +158,18 @@ public class SSHClient
}
/**
* Add a {@link HostKeyVerifier} that will verify any host at given {@code hostname:port} and a host key that has
* the given {@code fingerprint}, e.g. {@code "4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"}
* Add a {@link HostKeyVerifier} that will verify any host that's able to claim a host key with the given {@code
* fingerprint}, e.g. {@code "4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"}
*
* @param host the hostname / IP address
* @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)
*
* @see SecurityUtils#getFingerprint
*/
public void addHostKeyVerifier(final String host, final int port, final String fingerprint) {
public void addHostKeyVerifier(final String fingerprint) {
addHostKeyVerifier(new HostKeyVerifier() {
@Override
public boolean verify(String h, int p, PublicKey k) {
return host.equals(h) && port == p && SecurityUtils.getFingerprint(k).equals(fingerprint);
return SecurityUtils.getFingerprint(k).equals(fingerprint);
}
});
}
@@ -595,7 +595,7 @@ public class SSHClient
public SFTPClient newSFTPClient()
throws IOException {
assert isConnected() && isAuthenticated();
return new SFTPClient(this);
return new SFTPClient(new SFTPEngine(this).init());
}
/**

View File

@@ -18,39 +18,32 @@ package net.schmizz.sshj.common;
/** Disconnect error codes */
public enum DisconnectReason {
UNKNOWN(0),
HOST_NOT_ALLOWED_TO_CONNECT(1),
PROTOCOL_ERROR(2),
KEY_EXCHANGE_FAILED(3),
HOST_AUTHENTICATION_FAILED(4),
RESERVED(4),
MAC_ERROR(5),
COMPRESSION_ERROR(6),
SERVICE_NOT_AVAILABLE(7),
PROTOCOL_VERSION_NOT_SUPPORTED(8),
HOST_KEY_NOT_VERIFIABLE(9),
CONNECTION_LOST(10),
BY_APPLICATION(11),
TOO_MANY_CONNECTIONS(12),
AUTH_CANCELLED_BY_USER(13),
NO_MORE_AUTH_METHODS_AVAILABLE(14),
ILLEGAL_USER_NAME(15);
UNKNOWN,
HOST_NOT_ALLOWED_TO_CONNECT,
PROTOCOL_ERROR,
KEY_EXCHANGE_FAILED,
RESERVED,
MAC_ERROR,
COMPRESSION_ERROR,
SERVICE_NOT_AVAILABLE,
PROTOCOL_VERSION_NOT_SUPPORTED,
HOST_KEY_NOT_VERIFIABLE,
CONNECTION_LOST,
BY_APPLICATION,
TOO_MANY_CONNECTIONS,
AUTH_CANCELLED_BY_USER,
NO_MORE_AUTH_METHODS_AVAILABLE,
ILLEGAL_USER_NAME;
public static DisconnectReason fromInt(int code) {
for (DisconnectReason dc : values())
if (dc.code == code)
return dc;
return UNKNOWN;
}
private final int code;
private DisconnectReason(int code) {
this.code = code;
final int len = values().length;
if (code < 0 || code > len)
return UNKNOWN;
return values()[code];
}
public int toInt() {
return code;
return ordinal();
}
}

View File

@@ -40,16 +40,16 @@ public enum KeyType {
final BigInteger n = buf.readMPInt();
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final RSAPublicKey rsaKey = (RSAPublicKey) pk;
buf.putString(sType)
.putMPInt(rsaKey.getPublicExponent()) // e
.putMPInt(rsaKey.getModulus()); // n
}
@Override
protected boolean isMyType(Key key) {
return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey);
@@ -70,6 +70,7 @@ public enum KeyType {
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final DSAPublicKey dsaKey = (DSAPublicKey) pk;
@@ -120,7 +121,6 @@ public enum KeyType {
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
protected abstract boolean isMyType(Key key);
public static KeyType fromKey(Key key) {

View File

@@ -18,6 +18,7 @@ package net.schmizz.sshj.common;
/** SSH message identifiers */
public enum Message {
UNKNOWN(0),
DISCONNECT(1),
IGNORE(2),
UNIMPLEMENTED(3),
@@ -67,8 +68,11 @@ public enum Message {
static {
for (Message c : Message.values())
if (cache[c.toByte()] == null)
cache[c.toByte()] = c;
cache[c.toByte()] = c;
for (int i = 0; i < 256; i++) {
if (cache[i] == null)
cache[i] = UNKNOWN;
}
}
public static Message fromByte(byte b) {

View File

@@ -76,11 +76,7 @@ public class SSHPacket
* @return the message identifier
*/
public Message readMessageID() {
byte b = readByte();
Message cmd = Message.fromByte(b);
if (cmd == null)
throw new BufferException("Unknown message ID: " + b);
return cmd;
return Message.fromByte(readByte());
}
/**

View File

@@ -86,7 +86,7 @@ public class StreamCopier
return sb.toString();
}
private final Logger log;
private final Logger log = LoggerFactory.getLogger(getClass());
private final InputStream in;
private final OutputStream out;
@@ -103,9 +103,7 @@ public class StreamCopier
public StreamCopier(String name, InputStream in, OutputStream out) {
this.in = in;
this.out = out;
setName("streamCopier");
log = LoggerFactory.getLogger(name);
setName(name);
}
public StreamCopier bufSize(int size) {

View File

@@ -30,6 +30,7 @@ import net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
@@ -248,9 +249,9 @@ public class ConnectionImpl
public void notifyDisconnect()
throws SSHException {
super.notifyDisconnect();
FutureUtils.alertAll(new ConnectionException("Disconnected."), globalReqFutures);
for (Channel chan : channels.values())
chan.close();
final ConnectionException ex = new ConnectionException("Disconnected.");
FutureUtils.alertAll(ex, globalReqFutures);
ErrorNotifiable.Util.alertAll(ex, new HashSet<Channel>(channels.values()));
}
}

View File

@@ -62,7 +62,7 @@ public abstract class AbstractChannel
implements Channel {
/** Logger */
protected final Logger log;
protected final Logger log = LoggerFactory.getLogger(getClass());
/** Transport layer */
protected final Transport trans;
@@ -83,7 +83,7 @@ public abstract class AbstractChannel
/** Channel open event */
protected final Event<ConnectionException> open;
/** Channel close event */
private final Event<ConnectionException> close;
protected final Event<ConnectionException> close;
/* Access to these fields should be synchronized using this object */
private boolean eofSent;
@@ -109,9 +109,7 @@ public abstract class AbstractChannel
id = conn.nextID();
log = LoggerFactory.getLogger("chan#" + id);
lwin = new Window.Local(id, conn.getWindowSize(), conn.getMaxPacketSize());
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
in = new ChannelInputStream(this, trans, lwin);
open = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, lock);
@@ -120,7 +118,7 @@ public abstract class AbstractChannel
protected void init(int recipient, int remoteWinSize, int remoteMaxPacketSize) {
this.recipient = recipient;
rwin = new Window.Remote(id, remoteWinSize, remoteMaxPacketSize);
rwin = new Window.Remote(remoteWinSize, remoteMaxPacketSize);
out = new ChannelOutputStream(this, trans, rwin);
log.info("Initialized - {}", this);
}
@@ -269,6 +267,16 @@ public abstract class AbstractChannel
}
}
public void join()
throws ConnectionException {
close.await();
}
public void join(int timeout, TimeUnit unit)
throws ConnectionException {
close.await(timeout, unit);
}
protected synchronized void sendClose()
throws TransportException {
try {
@@ -304,7 +312,6 @@ public abstract class AbstractChannel
rwin.expand(howMuch);
}
/** Called when this channel's end-of-life has been reached. Subclasses may override but must call super. */
protected void finishOff() {
conn.forget(this);
close.set();
@@ -332,7 +339,7 @@ public abstract class AbstractChannel
protected void receiveInto(ChannelInputStream stream, SSHPacket buf)
throws ConnectionException, TransportException {
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);
if (log.isTraceEnabled())
log.trace("IN #{}: {}", id, ByteArrayUtils.printHex(buf.array(), buf.rpos(), len));

View File

@@ -23,6 +23,7 @@ import net.schmizz.sshj.transport.TransportException;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
/** A channel is the basic medium for application-layer data on top of an SSH transport. */
public interface Channel
@@ -135,4 +136,10 @@ public interface Channel
*/
void setAutoExpand(boolean autoExpand);
void join()
throws ConnectionException;
void join(int timeout, TimeUnit unit)
throws ConnectionException;
}

View File

@@ -59,7 +59,7 @@ public final class ChannelInputStream
extends InputStream
implements ErrorNotifiable {
private final Logger log;
private final Logger log = LoggerFactory.getLogger(getClass());
private final Channel chan;
private final Transport trans;
@@ -71,8 +71,6 @@ public final class ChannelInputStream
private SSHException error;
public ChannelInputStream(Channel chan, Transport trans, Window.Local win) {
log = LoggerFactory.getLogger("<< chan#" + chan.getID() + " / input stream >>");
this.chan = chan;
this.trans = trans;
this.win = win;

View File

@@ -22,7 +22,7 @@ import org.slf4j.LoggerFactory;
public abstract class Window {
protected final Logger log;
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Object lock = new Object();
@@ -30,8 +30,7 @@ public abstract class Window {
protected int size;
public Window(int chanID, String kindOfWindow, int initialWinSize, int maxPacketSize) {
log = LoggerFactory.getLogger("<< chan#" + chanID + " / " + kindOfWindow + " >>");
public Window(int initialWinSize, int maxPacketSize) {
size = initialWinSize;
this.maxPacketSize = maxPacketSize;
}
@@ -70,8 +69,8 @@ public abstract class Window {
public static final class Remote
extends Window {
public Remote(int chanID, int initialWinSize, int maxPacketSize) {
super(chanID, "remote win", initialWinSize, maxPacketSize);
public Remote(int initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
}
public void waitAndConsume(int howMuch)
@@ -98,8 +97,8 @@ public abstract class Window {
private final int initialSize;
private final int threshold;
public Local(int chanID, int initialWinSize, int maxPacketSize) {
super(chanID, "local win", initialWinSize, maxPacketSize);
public Local(int initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
this.initialSize = initialWinSize;
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
}

View File

@@ -35,10 +35,7 @@
*/
package net.schmizz.sshj.connection.channel.direct;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.common.*;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.ChannelInputStream;
@@ -50,9 +47,10 @@ import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/** {@link Session} implementation. */
public class
SessionChannel
/**
* {@link Session} implementation.
*/
public class SessionChannel
extends AbstractDirectChannel
implements Session, Session.Command, Session.Shell, Session.Subsystem {
@@ -66,6 +64,8 @@ public class
private Boolean canDoFlowControl;
private boolean usedUp;
public SessionChannel(Connection conn) {
super(conn, "session");
}
@@ -73,7 +73,7 @@ public class
@Override
public void allocateDefaultPTY()
throws ConnectionException, TransportException {
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
allocatePTY("dummy", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
}
@Override
@@ -114,9 +114,11 @@ public class
@Override
public Command exec(String command)
throws ConnectionException, TransportException {
checkReuse();
log.info("Will request to exec `{}`", command);
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
.await(conn.getTimeout(), TimeUnit.SECONDS);
usedUp = true;
return this;
}
@@ -170,8 +172,7 @@ public class
@Override
public void reqX11Forwarding(String authProto, String authCookie, int screen)
throws ConnectionException,
TransportException {
throws ConnectionException, TransportException {
sendChannelRequest(
"x11-req",
true,
@@ -199,16 +200,20 @@ public class
@Override
public Shell startShell()
throws ConnectionException, TransportException {
checkReuse();
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
usedUp = true;
return this;
}
@Override
public Subsystem startSubsystem(String name)
throws ConnectionException, TransportException {
checkReuse();
log.info("Will request `{}` subsystem", name);
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
.await(conn.getTimeout(), TimeUnit.SECONDS);
usedUp = true;
return this;
}
@@ -238,4 +243,15 @@ public class
super.gotExtendedData(dataTypeCode, buf);
}
}
@Override
public void notifyError(SSHException error) {
err.notifyError(error);
super.notifyError(error);
}
private void checkReuse() {
if (usedUp)
throw new SSHRuntimeException("This session channel is all used up");
}
}

View File

@@ -19,21 +19,20 @@ 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. */
public enum Signal {
ABRT("ABRT"),
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");
ABRT,
ALRM,
FPE,
HUP,
ILL,
INT,
KILL,
PIPE,
QUIT,
SEGV,
TERM,
USR1,
USR2,
UNKNOWN;
/**
* Create from the string representation used when the signal is received as part of an SSH packet.
@@ -44,20 +43,9 @@ public enum Signal {
*/
public static Signal fromString(String name) {
for (Signal sig : Signal.values())
if (sig.name.equals(name))
if (sig.toString().equals(name))
return sig;
return UNKNOWN;
}
private final String name;
private Signal(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@@ -34,9 +34,11 @@ public class PacketReader
private final Map<Long, Future<Response, SFTPException>> futures = new ConcurrentHashMap<Long, Future<Response, SFTPException>>();
private final SFTPPacket<Response> packet = new SFTPPacket<Response>();
private final byte[] lenBuf = new byte[4];
private final SFTPEngine engine;
public PacketReader(InputStream in) {
this.in = in;
public PacketReader(SFTPEngine engine) {
this.engine = engine;
this.in = engine.getSubsystem().getInputStream();
setName("sftp reader");
}
@@ -78,7 +80,7 @@ public class PacketReader
@Override
public void run() {
try {
while (true) {
while (!isInterrupted()) {
readPacket();
handle();
}
@@ -90,7 +92,7 @@ public class PacketReader
public void handle()
throws SFTPException {
Response resp = new Response(packet);
Response resp = new Response(packet, engine.getOperativeProtocolVersion());
Future<Response, SFTPException> future = futures.remove(resp.getRequestID());
log.debug("Received {} packet", resp.getType());
if (future == null)

View File

@@ -52,8 +52,7 @@ public enum PacketType {
static {
for (PacketType t : PacketType.values())
if (cache[t.toByte() & 0xff] == null)
cache[t.toByte() & 0xff] = t;
cache[t.toByte() & 0xff] = t;
}
private PacketType(int b) {

View File

@@ -19,11 +19,11 @@ import java.io.IOException;
public class PathHelper {
private final SFTPEngine sftp;
private final SFTPEngine engine;
private String dotDir;
public PathHelper(SFTPEngine sftp) {
this.sftp = sftp;
public PathHelper(SFTPEngine engine) {
this.engine = engine;
}
public PathComponents getComponents(String path)
@@ -56,7 +56,7 @@ public class PathHelper {
private String canon(String path)
throws IOException {
return sftp.canonicalize(path);
return engine.canonicalize(path);
}
}

View File

@@ -21,7 +21,7 @@ import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
abstract class RemoteResource
public abstract class RemoteResource
implements Closeable {
/** Logger */

View File

@@ -47,15 +47,21 @@ public class Response
}
private final int protocolVersion;
private final PacketType type;
private final long reqID;
public Response(Buffer<Response> pk) {
public Response(Buffer<Response> pk, int protocolVersion) {
super(pk);
this.protocolVersion = protocolVersion;
this.type = readType();
this.reqID = readLong();
}
public int getProtocolVersion() {
return protocolVersion;
}
public long getRequestID() {
return reqID;
}
@@ -72,7 +78,7 @@ public class Response
throws SFTPException {
if (getType() != pt)
if (getType() == PacketType.STATUS)
throw new SFTPException(readStatusCode(), readString());
error(readStatusCode());
else
throw new SFTPException("Unexpected packet " + getType());
return this;
@@ -85,10 +91,15 @@ public class Response
public Response ensureStatusIs(StatusCode acceptable)
throws SFTPException {
StatusCode sc = readStatusCode();
final StatusCode sc = readStatusCode();
if (sc != acceptable)
throw new SFTPException(sc, readString());
error(sc);
return this;
}
protected String error(StatusCode sc)
throws SFTPException {
throw new SFTPException(sc, protocolVersion < 3 ? sc.toString() : readString());
}
}

View File

@@ -15,11 +15,11 @@
*/
package net.schmizz.sshj.sftp;
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import net.schmizz.sshj.xfer.FilePermission;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.util.Deque;
import java.util.EnumSet;
@@ -27,24 +27,24 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class SFTPClient {
public class SFTPClient
implements Closeable {
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
private final SFTPEngine sftp;
private final SFTPEngine engine;
private final SFTPFileTransfer xfer;
private final PathHelper pathHelper;
public SFTPClient(SessionFactory ssh)
throws IOException {
this.sftp = new SFTPEngine(ssh).init();
this.pathHelper = new PathHelper(sftp);
this.xfer = new SFTPFileTransfer(sftp);
public SFTPClient(SFTPEngine engine) {
this.engine = engine;
this.pathHelper = new PathHelper(engine);
this.xfer = new SFTPFileTransfer(engine);
}
public SFTPEngine getSFTPEngine() {
return sftp;
return engine;
}
public SFTPFileTransfer getFileTansfer() {
@@ -58,7 +58,7 @@ public class SFTPClient {
public List<RemoteResourceInfo> ls(String path, RemoteResourceFilter filter)
throws IOException {
final RemoteDirectory dir = sftp.openDir(path);
final RemoteDirectory dir = engine.openDir(path);
try {
return dir.scan(filter);
} finally {
@@ -69,7 +69,7 @@ public class SFTPClient {
public RemoteFile open(String filename, Set<OpenMode> mode, FileAttributes attrs)
throws IOException {
log.debug("Opening `{}`", filename);
return sftp.open(filename, mode, attrs);
return engine.open(filename, mode, attrs);
}
public RemoteFile open(String filename, Set<OpenMode> mode)
@@ -84,7 +84,7 @@ public class SFTPClient {
public void mkdir(String dirname)
throws IOException {
sftp.makeDir(dirname);
engine.makeDir(dirname);
}
public void mkdirs(String path)
@@ -109,7 +109,7 @@ public class SFTPClient {
public FileAttributes statExistence(String path)
throws IOException {
try {
return sftp.stat(path);
return engine.stat(path);
} catch (SFTPException sftpe) {
if (sftpe.getStatusCode() == Response.StatusCode.NO_SUCH_FILE) {
return null;
@@ -121,31 +121,31 @@ public class SFTPClient {
public void rename(String oldpath, String newpath)
throws IOException {
sftp.rename(oldpath, newpath);
engine.rename(oldpath, newpath);
}
public void rm(String filename)
throws IOException {
sftp.remove(filename);
engine.remove(filename);
}
public void rmdir(String dirname)
throws IOException {
sftp.removeDir(dirname);
engine.removeDir(dirname);
}
public void symlink(String linkpath, String targetpath)
throws IOException {
sftp.symlink(linkpath, targetpath);
engine.symlink(linkpath, targetpath);
}
public int version() {
return sftp.getOperativeProtocolVersion();
return engine.getOperativeProtocolVersion();
}
public void setattr(String path, FileAttributes attrs)
throws IOException {
sftp.setAttributes(path, attrs);
engine.setAttributes(path, attrs);
}
public int uid(String path)
@@ -185,17 +185,17 @@ public class SFTPClient {
public String readlink(String path)
throws IOException {
return sftp.readLink(path);
return engine.readLink(path);
}
public FileAttributes stat(String path)
throws IOException {
return sftp.stat(path);
return engine.stat(path);
}
public FileAttributes lstat(String path)
throws IOException {
return sftp.lstat(path);
return engine.lstat(path);
}
public void chown(String path, int uid)
@@ -220,7 +220,7 @@ public class SFTPClient {
public String canonicalize(String path)
throws IOException {
return sftp.canonicalize(path);
return engine.canonicalize(path);
}
public long size(String path)
@@ -238,4 +238,10 @@ public class SFTPClient {
xfer.upload(source, dest);
}
@Override
public void close()
throws IOException {
engine.close();
}
}

View File

@@ -21,6 +21,7 @@ import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.util.EnumSet;
@@ -30,39 +31,34 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
public class SFTPEngine
implements Requester {
/** Logger */
private final Logger log = LoggerFactory.getLogger(getClass());
public static final int PROTOCOL_VERSION = 3;
implements Requester, Closeable {
public static final int MAX_SUPPORTED_VERSION = 3;
public static final int DEFAULT_TIMEOUT = 30;
private volatile int timeout = DEFAULT_TIMEOUT;
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
private final Subsystem sub;
private final PacketReader reader;
private final OutputStream out;
protected volatile int timeout = DEFAULT_TIMEOUT;
private long reqID;
private int negotiatedVersion;
private final Map<String, String> serverExtensions = new HashMap<String, String>();
protected final Subsystem sub;
protected final PacketReader reader;
protected final OutputStream out;
protected long reqID;
protected int operativeVersion;
protected final Map<String, String> serverExtensions = new HashMap<String, String>();
public SFTPEngine(SessionFactory ssh)
throws SSHException {
sub = ssh.startSession().startSubsystem("sftp");
out = sub.getOutputStream();
reader = new PacketReader(sub.getInputStream());
}
public Subsystem getSubsystem() {
return sub;
reader = new PacketReader(this);
}
public SFTPEngine init()
throws IOException {
transmit(new SFTPPacket<Request>(PacketType.INIT).putInt(PROTOCOL_VERSION));
transmit(new SFTPPacket<Request>(PacketType.INIT).putInt(MAX_SUPPORTED_VERSION));
final SFTPPacket<Response> response = reader.readPacket();
@@ -70,10 +66,10 @@ public class SFTPEngine
if (type != PacketType.VERSION)
throw new SFTPException("Expected INIT packet, received: " + type);
negotiatedVersion = response.readInt();
log.info("Client version {}, server version {}", PROTOCOL_VERSION, negotiatedVersion);
if (negotiatedVersion < PROTOCOL_VERSION)
throw new SFTPException("Server reported protocol version: " + negotiatedVersion);
operativeVersion = response.readInt();
log.info("Server version {}", operativeVersion);
if (MAX_SUPPORTED_VERSION < operativeVersion)
throw new SFTPException("Server reported incompatible protocol version: " + operativeVersion);
while (response.available() > 0)
serverExtensions.put(response.readString(), response.readString());
@@ -83,8 +79,16 @@ public class SFTPEngine
return this;
}
public Subsystem getSubsystem() {
return sub;
}
public int getOperativeProtocolVersion() {
return negotiatedVersion;
return operativeVersion;
}
public Request newExtendedRequest(String reqName) {
return newRequest(PacketType.EXTENDED).putString(reqName);
}
@Override
@@ -101,17 +105,6 @@ public class SFTPEngine
return req.getResponseFuture().get(timeout, TimeUnit.SECONDS);
}
private synchronized void transmit(SFTPPacket<Request> payload)
throws IOException {
final int len = payload.available();
out.write((len >>> 24) & 0xff);
out.write((len >>> 16) & 0xff);
out.write((len >>> 8) & 0xff);
out.write(len & 0xff);
out.write(payload.array(), payload.rpos(), len);
out.flush();
}
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
throws IOException {
final String handle = doRequest(
@@ -147,6 +140,8 @@ public class SFTPEngine
public String readLink(String path)
throws IOException {
if (operativeVersion < 3)
throw new SFTPException("READLINK is not supported in SFTPv" + operativeVersion);
return readSingleName(
doRequest(
newRequest(PacketType.READLINK).putString(path)
@@ -165,6 +160,8 @@ public class SFTPEngine
public void symlink(String linkpath, String targetpath)
throws IOException {
if (operativeVersion < 3)
throw new SFTPException("SYMLINK is not supported in SFTPv" + operativeVersion);
doRequest(
newRequest(PacketType.SYMLINK).putString(linkpath).putString(targetpath)
).ensureStatusPacketIsOK();
@@ -184,13 +181,6 @@ public class SFTPEngine
).ensureStatusIs(Response.StatusCode.OK);
}
private FileAttributes stat(PacketType pt, String path)
throws IOException {
return doRequest(newRequest(pt).putString(path))
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
public FileAttributes stat(String path)
throws IOException {
return stat(PacketType.STAT, path);
@@ -203,6 +193,8 @@ public class SFTPEngine
public void rename(String oldPath, String newPath)
throws IOException {
if (operativeVersion < 1)
throw new SFTPException("RENAME is not supported in SFTPv" + operativeVersion);
doRequest(
newRequest(PacketType.RENAME).putString(oldPath).putString(newPath)
).ensureStatusPacketIsOK();
@@ -216,15 +208,6 @@ public class SFTPEngine
));
}
private static String readSingleName(Response res)
throws IOException {
res.ensurePacketTypeIs(PacketType.NAME);
if (res.readInt() == 1)
return res.readString();
else
throw new SFTPException("Unexpected data in " + res.getType() + " packet");
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@@ -233,4 +216,37 @@ public class SFTPEngine
return timeout;
}
@Override
public void close()
throws IOException {
sub.close();
}
protected FileAttributes stat(PacketType pt, String path)
throws IOException {
return doRequest(newRequest(pt).putString(path))
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
protected static String readSingleName(Response res)
throws IOException {
res.ensurePacketTypeIs(PacketType.NAME);
if (res.readInt() == 1)
return res.readString();
else
throw new SFTPException("Unexpected data in " + res.getType() + " packet");
}
protected synchronized void transmit(SFTPPacket<Request> payload)
throws IOException {
final int len = payload.available();
out.write((len >>> 24) & 0xff);
out.write((len >>> 16) & 0xff);
out.write((len >>> 8) & 0xff);
out.write(len & 0xff);
out.write(payload.array(), payload.rpos(), len);
out.flush();
}
}

View File

@@ -67,7 +67,6 @@ public class SFTPException
public StatusCode getStatusCode() {
return (sc == null) ? StatusCode.UNKNOWN : sc;
}
public SFTPException(StatusCode sc, String msg) {

View File

@@ -33,7 +33,7 @@ public class SFTPFileTransfer
extends AbstractFileTransfer
implements FileTransfer {
private final SFTPEngine sftp;
private final SFTPEngine engine;
private final PathHelper pathHelper;
private volatile FileFilter uploadFilter = defaultLocalFilter;
@@ -53,9 +53,9 @@ public class SFTPFileTransfer
}
};
public SFTPFileTransfer(SFTPEngine sftp) {
this.sftp = sftp;
this.pathHelper = new PathHelper(sftp);
public SFTPFileTransfer(SFTPEngine engine) {
this.engine = engine;
this.pathHelper = new PathHelper(engine);
}
@Override
@@ -68,7 +68,7 @@ public class SFTPFileTransfer
public void download(String source, String dest)
throws IOException {
final PathComponents pathComponents = pathHelper.getComponents(source);
final FileAttributes attributes = sftp.stat(source);
final FileAttributes attributes = engine.stat(source);
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
}
@@ -119,7 +119,7 @@ public class SFTPFileTransfer
private File downloadDir(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
final RemoteDirectory rd = sftp.openDir(remote.getPath());
final RemoteDirectory rd = engine.openDir(remote.getPath());
try {
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
download(rri, new File(adjusted.getPath(), rri.getName()));
@@ -132,11 +132,11 @@ public class SFTPFileTransfer
private File downloadFile(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
final RemoteFile rf = sftp.open(remote.getPath());
final RemoteFile rf = engine.open(remote.getPath());
try {
final FileOutputStream fos = new FileOutputStream(adjusted);
try {
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
StreamCopier.copy(rf.getInputStream(), fos, engine.getSubsystem()
.getLocalMaxPacketSize(), false, listener);
} finally {
fos.close();
@@ -176,7 +176,7 @@ public class SFTPFileTransfer
listener.finishedFile();
} else
throw new IOException(local + " is not a file or directory");
sftp.setAttributes(adjustedPath, getAttributes(local));
engine.setAttributes(adjustedPath, getAttributes(local));
}
private String uploadDir(File local, String remote)
@@ -190,13 +190,13 @@ public class SFTPFileTransfer
private String uploadFile(File local, String remote)
throws IOException {
final String adjusted = prepareFile(local, remote);
final RemoteFile rf = sftp.open(adjusted, EnumSet.of(OpenMode.WRITE,
OpenMode.CREAT,
OpenMode.TRUNC));
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
OpenMode.CREAT,
OpenMode.TRUNC));
try {
final FileInputStream fis = new FileInputStream(local);
try {
final int bufSize = sftp.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead();
final int bufSize = engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead();
StreamCopier.copy(fis, rf.getOutputStream(), bufSize, false, listener);
} finally {
fis.close();
@@ -211,11 +211,11 @@ public class SFTPFileTransfer
throws IOException {
final FileAttributes attrs;
try {
attrs = sftp.stat(remote);
attrs = engine.stat(remote);
} catch (SFTPException e) {
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
log.debug("probeDir: {} does not exist, creating", remote);
sftp.makeDir(remote);
engine.makeDir(remote);
return remote;
} else
throw e;
@@ -237,7 +237,7 @@ public class SFTPFileTransfer
throws IOException {
final FileAttributes attrs;
try {
attrs = sftp.stat(remote);
attrs = engine.stat(remote);
} catch (SFTPException e) {
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
log.debug("probeFile: {} does not exist", remote);

View File

@@ -15,8 +15,6 @@
*/
package net.schmizz.sshj.sftp;
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import java.io.IOException;
import java.util.List;
import java.util.Set;
@@ -26,9 +24,9 @@ public class StatefulSFTPClient
private String cwd;
public StatefulSFTPClient(SessionFactory ssh)
public StatefulSFTPClient(SFTPEngine engine)
throws IOException {
super(ssh);
super(engine);
this.cwd = getSFTPEngine().canonicalize(".");
log.info("Start dir = " + cwd);
}
@@ -183,7 +181,7 @@ public class StatefulSFTPClient
@Override
public void put(String source, String dest)
throws IOException {
super.get(source, cwdify(dest));
super.put(source, cwdify(dest));
}
}

View File

@@ -50,8 +50,6 @@ final class Heartbeater
private int interval;
private boolean started;
Heartbeater(TransportImpl trans) {
this.trans = trans;
setName("heartbeater");
@@ -59,36 +57,36 @@ final class Heartbeater
synchronized void setInterval(int interval) {
this.interval = interval;
if (interval != 0) {
if (!started)
start();
notify();
}
if (interval > 0 && getState() == Thread.State.NEW)
start();
notify();
}
synchronized int getInterval() {
return interval;
}
synchronized private int getPositiveInterval()
throws InterruptedException {
while (interval <= 0)
wait();
return interval;
}
@Override
public void run() {
log.debug("Starting");
try {
while (!Thread.currentThread().isInterrupted()) {
int hi;
synchronized (this) {
while ((hi = interval) == 0)
wait();
}
if (!started)
started = true;
else if (trans.isRunning()) {
while (!isInterrupted()) {
final int hi = getPositiveInterval();
if (trans.isRunning()) {
log.info("Sending heartbeat since {} seconds elapsed", hi);
trans.write(new SSHPacket(Message.IGNORE));
}
Thread.sleep(hi * 1000);
}
} catch (Exception e) {
if (Thread.currentThread().isInterrupted()) {
if (isInterrupted()) {
// We are meant to shut up and draw to a close if interrupted
} else
trans.die(e);
@@ -96,4 +94,5 @@ final class Heartbeater
log.debug("Stopping");
}
}

View File

@@ -92,8 +92,7 @@ final class KeyExchanger
private Proposal clientProposal;
private NegotiatedAlgorithms negotiatedAlgs;
private final Event<TransportException> kexInitSent = new Event<TransportException>("kexinit sent",
TransportException.chainer);
private final Event<TransportException> kexInitSent = new Event<TransportException>("kexinit sent", TransportException.chainer);
private final Event<TransportException> done;

View File

@@ -41,22 +41,20 @@ import org.slf4j.LoggerFactory;
import java.io.InputStream;
final class Reader
public final class Reader
extends Thread {
private final Logger log = LoggerFactory.getLogger(getClass());
private final TransportImpl trans;
Reader(TransportImpl trans) {
public Reader(TransportImpl trans) {
this.trans = trans;
setName("reader");
}
@Override
public void run() {
final Thread curThread = Thread.currentThread();
try {
final Decoder decoder = trans.getDecoder();
@@ -66,7 +64,7 @@ final class Reader
int needed = 1;
while (!curThread.isInterrupted()) {
while (!isInterrupted()) {
int read = inp.read(recvbuf, 0, needed);
if (read == -1)
throw new TransportException("Broken transport; encountered EOF");
@@ -75,7 +73,7 @@ final class Reader
}
} catch (Exception e) {
if (curThread.isInterrupted()) {
if (isInterrupted()) {
// We are meant to shut up and draw to a close if interrupted
} else
trans.die(e);

View File

@@ -421,8 +421,8 @@ public final class TransportImpl
.putInt(reason.toInt())
.putString(message)
.putString(""));
} catch (IOException logged) {
log.warn("Error writing packet: {}", logged);
} catch (IOException worthless) {
log.debug("Error writing packet: {}", worthless.toString());
}
}

View File

@@ -224,7 +224,7 @@ public class UserAuthImpl
}
private void saveException(UserAuthException e) {
log.error("Saving for later - {}", e.toString());
log.debug("Saving for later - {}", e.toString());
savedEx.push(e);
}

View File

@@ -19,8 +19,6 @@ import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.userauth.UserAuthException;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
// TODO check if this even works...!
/** Implements the {@code hostbased} SSH authentication method. */
public class AuthHostbased
extends KeyedAuthMethod {
@@ -28,22 +26,17 @@ public class AuthHostbased
protected final String hostname;
protected final String hostuser;
public AuthHostbased(KeyProvider kProv, String hostuser) {
this(kProv, hostuser, null);
}
public AuthHostbased(KeyProvider kProv, String hostuser, String hostname) {
public AuthHostbased(KeyProvider kProv, String hostname, String hostuser) {
super("hostbased", kProv);
assert hostuser != null;
this.hostuser = hostuser;
this.hostname = hostname;
this.hostuser = hostuser;
}
@Override
protected SSHPacket buildReq()
throws UserAuthException {
SSHPacket req = putPubKey(super.buildReq());
req.putString(hostname == null ? params.getTransport().getRemoteHost() : hostname).putString(hostuser);
final SSHPacket req = putPubKey(super.buildReq());
req.putString(hostname).putString(hostuser);
return putSig(req);
}

View File

@@ -49,7 +49,6 @@ public abstract class KeyedAuthMethod
// public key as 2 strings: [ key type | key blob ]
reqBuf.putString(KeyType.fromKey(key).toString())
.putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData());
return reqBuf;
}

View File

@@ -15,6 +15,9 @@
*/
package net.schmizz.sshj.xfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
@@ -26,6 +29,8 @@ import java.io.IOException;
public class DefaultModeSetter
implements ModeSetter {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public void setLastAccessedTime(File f, long t)
throws IOException {
@@ -36,7 +41,7 @@ public class DefaultModeSetter
public void setLastModifiedTime(File f, long t)
throws IOException {
if (!f.setLastModified(t * 1000))
throw new IOException("Error setting last modified time for " + f);
log.warn("Could not set last modified time for {} to {}", f, t);
}
@Override
@@ -49,7 +54,7 @@ public class DefaultModeSetter
final boolean x = f.setExecutable(FilePermission.USR_X.isIn(perms),
!(FilePermission.OTH_X.isIn(perms) || FilePermission.GRP_X.isIn(perms)));
if (!(r && w && x))
throw new IOException("Error setting permissions for " + f);
log.warn("Could not set permissions for {} to {}", f, Integer.toString(perms, 16));
}
@Override

View File

@@ -68,13 +68,13 @@ public enum FilePermission {
}
public boolean isIn(int mask) {
return (mask & val) == mask;
return (mask & val) == val;
}
public static Set<FilePermission> fromMask(int mask) {
List<FilePermission> perms = new LinkedList<FilePermission>();
final List<FilePermission> perms = new LinkedList<FilePermission>();
for (FilePermission p : FilePermission.values())
if ((mask & p.val) == p.val)
if (p.isIn(mask))
perms.add(p);
return new HashSet<FilePermission>(perms);
}

View File

@@ -123,9 +123,6 @@ public final class SCPDownloadClient
return true;
case (char) 1:
addWarning(msg.substring(1));
break;
case (char) 2:
throw new SCPException("Remote SCP command returned error: " + msg.substring(1));

View File

@@ -61,7 +61,6 @@ abstract class SCPEngine {
final SessionFactory host;
final TransferListener listener;
final Queue<String> warnings = new LinkedList<String>();
Command scp;
int exitStatus;
@@ -86,19 +85,6 @@ abstract class SCPEngine {
return exitStatus;
}
public Queue<String> getWarnings() {
return warnings;
}
public boolean hadWarnings() {
return !warnings.isEmpty();
}
void addWarning(String warning) {
log.warn(warning);
warnings.add(warning);
}
void check(String what)
throws IOException {
int code = scp.getInputStream().read();
@@ -111,9 +97,7 @@ abstract class SCPEngine {
case 0: // OK
log.debug(what);
return;
case 1:
addWarning(readMessage());
break;
case 1: // Warning? not
case 2:
throw new SCPException("Remote SCP command had error: " + readMessage());
default:
@@ -123,7 +107,6 @@ abstract class SCPEngine {
void cleanSlate() {
exitStatus = -1;
warnings.clear();
}
void execSCPWith(List<Arg> args, String path)

View File

@@ -57,7 +57,7 @@ public class SmokeTest {
sshd.start();
ssh = new SSHClient();
ssh.addHostKeyVerifier(hostname, port, fingerprint);
ssh.addHostKeyVerifier(fingerprint);
}
@After