mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8cfc796af | ||
|
|
d9c0c6725c | ||
|
|
b2297c6b44 | ||
|
|
e10ad28f2f | ||
|
|
61fc00a90a | ||
|
|
c8ef7ff0ca | ||
|
|
e6c4f6ae69 | ||
|
|
3418df7a56 | ||
|
|
0ddd1f38c5 | ||
|
|
0ec6918d7a | ||
|
|
88a88c5dba | ||
|
|
6656214803 | ||
|
|
c781724028 | ||
|
|
eefaa26882 | ||
|
|
0d52441f01 | ||
|
|
9539ff6b7a | ||
|
|
1ced1d4fdc | ||
|
|
77924fd0be | ||
|
|
3f195649fa | ||
|
|
42a4358f5c | ||
|
|
61ce0f4868 | ||
|
|
777995af3b | ||
|
|
635cf88acd | ||
|
|
ce515fddcd | ||
|
|
9acff6202c | ||
|
|
cbd118e0b1 | ||
|
|
a8cf749d95 | ||
|
|
f3d4707ef0 | ||
|
|
4c5da634ad | ||
|
|
2fdafb76fd | ||
|
|
80b164a299 | ||
|
|
75418f33b7 | ||
|
|
732de2b605 | ||
|
|
4fb56b868f | ||
|
|
a877ec1448 | ||
|
|
b44631ea97 | ||
|
|
a50962ba2f | ||
|
|
e8215e4af2 | ||
|
|
3c2bda3196 | ||
|
|
b13e22084b | ||
|
|
e7ba0e1e26 | ||
|
|
f712720538 | ||
|
|
540708e540 | ||
|
|
e4d3a1f866 | ||
|
|
33969340e2 | ||
|
|
d65df3c9bc | ||
|
|
d2b9248535 | ||
|
|
431be8e7c7 | ||
|
|
885c602ab8 | ||
|
|
8262e8fc98 | ||
|
|
844c5d7f77 | ||
|
|
fb690c4fb0 | ||
|
|
ab04596a20 | ||
|
|
9ffdc35f93 | ||
|
|
93e23f4cfb | ||
|
|
504637099d | ||
|
|
cafd9217bf | ||
|
|
c627fabebd | ||
|
|
1c4781a65d | ||
|
|
aac7af2827 | ||
|
|
11c286b9b9 | ||
|
|
7fae513fd8 | ||
|
|
53ad9d2288 | ||
|
|
ee07072846 | ||
|
|
d38bbbcdf7 | ||
|
|
bc59c81dbc | ||
|
|
d70d37cf4e | ||
|
|
777d82912c | ||
|
|
f5db3e1563 | ||
|
|
7e524f5c6f | ||
|
|
dbb3f62e82 | ||
|
|
16a363fef6 | ||
|
|
9b0d39a798 | ||
|
|
81e36153d7 | ||
|
|
3026be282a | ||
|
|
8eedeb25fa | ||
|
|
de11880648 | ||
|
|
1ff4772f3f | ||
|
|
22a5ffe735 | ||
|
|
7a77f85ced | ||
|
|
0002fe8b40 | ||
|
|
3028e7f218 | ||
|
|
333e1cb7b8 | ||
|
|
945d430916 | ||
|
|
73b903784a | ||
|
|
7d53649a85 | ||
|
|
e193db9a14 | ||
|
|
a942edb911 | ||
|
|
137a7f5956 | ||
|
|
718ff503df | ||
|
|
d933b2538e | ||
|
|
ea6f9ceed2 | ||
|
|
07c61b14e8 | ||
|
|
4b175e6938 | ||
|
|
f7e47cffa0 | ||
|
|
42dddc7f7e | ||
|
|
f1b3dbb102 | ||
|
|
f83bf2cd3f | ||
|
|
be11cbb848 | ||
|
|
43b0599e1f | ||
|
|
b218186cae | ||
|
|
184236c3d5 | ||
|
|
cb1d773659 | ||
|
|
378665cb46 | ||
|
|
a5272dc413 | ||
|
|
60552fd001 | ||
|
|
ef082c668a | ||
|
|
e66386eb1c | ||
|
|
0937ec9800 | ||
|
|
4b2f42804e | ||
|
|
01765d24d2 | ||
|
|
1a2351c5ee | ||
|
|
1cec011401 | ||
|
|
52338c13cb | ||
|
|
09cf21f61a | ||
|
|
04c2e7b6b8 | ||
|
|
822f196dd8 | ||
|
|
a88a574b10 | ||
|
|
5cd6986355 | ||
|
|
b5d206bbcb | ||
|
|
4eae26c551 | ||
|
|
b950f88f52 | ||
|
|
3267860db4 | ||
|
|
d6eb5a040e | ||
|
|
21da5b9f65 | ||
|
|
6b66a952d4 | ||
|
|
aa4faf3f25 | ||
|
|
4be02450dd | ||
|
|
0cec27c28e | ||
|
|
4384367a1b | ||
|
|
4549648a76 | ||
|
|
20e2161022 | ||
|
|
fb0f3afa17 | ||
|
|
114c2bb424 | ||
|
|
079bde5dbf | ||
|
|
eaee42b017 | ||
|
|
8b61d96808 | ||
|
|
73fcc81e83 | ||
|
|
0f7926d4fa | ||
|
|
ca6f15650a | ||
|
|
eb78dc499d | ||
|
|
a852f33a15 | ||
|
|
ccabc1a20c | ||
|
|
cb2986d32e | ||
|
|
dc70f08e45 | ||
|
|
bf68ec18b2 | ||
|
|
7e78260ca9 | ||
|
|
27c60cee60 | ||
|
|
551b8b4fcf | ||
|
|
fd591e70be |
10
CONTRIBUTORS
10
CONTRIBUTORS
@@ -1,3 +1,11 @@
|
||||
Shikhar Bhushan <shikhar@schmizz.net>
|
||||
Cyril Ledru <cledru@keynectis.net>
|
||||
Incendium <incendium@gmail.com>
|
||||
Incendium <incendium@gmail.com>
|
||||
Philip Langdale <philipl@cloudera.com>
|
||||
Adar Dembo <adar@cloudera.com>
|
||||
Ioannis Canellos <iocanel@gmail.com>
|
||||
Neil Prosser <neil.prosser@gmail.com>
|
||||
hierynomus <jeroen@hierynomus.com>
|
||||
Ryan Tenney <ryan@10e.us>
|
||||
Aled Sage <aled.sage@gmail.com>
|
||||
Urs Reupke <ur@idos.de>
|
||||
|
||||
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
||||
sshj - SSHv2 library for Java
|
||||
Copyright 2010-2011 sshj contributors
|
||||
Copyright 2010-2012 sshj contributors
|
||||
|
||||
This product includes code derived from software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/):
|
||||
|
||||
@@ -39,6 +39,15 @@ Dependencies
|
||||
|
||||
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.
|
||||
|
||||
Reporting bugs
|
||||
----------------
|
||||
|
||||
`Issue tracker <https://github.com/shikhar/sshj/issues>`_
|
||||
|
||||
Discussion
|
||||
------------
|
||||
|
||||
`Google Group <http://groups.google.com/group/sshj-users>`_
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
100
pom.xml
100
pom.xml
@@ -5,8 +5,8 @@
|
||||
|
||||
<groupId>net.schmizz</groupId>
|
||||
<artifactId>sshj</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.4.0</version>
|
||||
<packaging>bundle</packaging>
|
||||
<version>0.9.0</version>
|
||||
|
||||
<name>sshj</name>
|
||||
<description>SSHv2 library for Java</description>
|
||||
@@ -23,7 +23,8 @@
|
||||
<connection>scm:git:git://github.com/shikhar/sshj.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:shikhar/sshj.git</developerConnection>
|
||||
<url>http://github.com/shikhar/sshj</url>
|
||||
</scm>
|
||||
<tag>v0.9.0</tag>
|
||||
</scm>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
@@ -33,46 +34,63 @@
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk16</artifactId>
|
||||
<version>1.45</version>
|
||||
<scope>provided</scope>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.49</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.1</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.49</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jzlib</artifactId>
|
||||
<version>1.0.7</version>
|
||||
<version>1.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>0.4.0</version>
|
||||
<version>0.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>0.9.24</version>
|
||||
<version>1.0.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.24</version>
|
||||
<version>1.0.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -96,6 +114,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>examples/*.java</exclude>
|
||||
@@ -107,29 +126,15 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.2-beta-5</version>
|
||||
<version>2.4.1</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assemble/examples.xml</descriptor>
|
||||
</descriptors>
|
||||
<mavenExecutorId>forked-path</mavenExecutorId>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
@@ -142,6 +147,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
@@ -154,6 +160,25 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>
|
||||
!net.schmizz.*,
|
||||
javax.crypto*,
|
||||
com.jcraft.jzlib*;version="[1.1,2)",
|
||||
org.slf4j*;version="[1.7,5)",
|
||||
org.bouncycastle*,
|
||||
*
|
||||
</Import-Package>
|
||||
<Export-Package>net.schmizz.*</Export-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -176,8 +201,8 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk16</artifactId>
|
||||
<version>1.45</version>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.49</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
@@ -187,12 +212,12 @@
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>0.9.24</version>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.24</version>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
@@ -209,7 +234,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.4</version>
|
||||
<configuration>
|
||||
<passphrase>${gpg.passphrase}</passphrase>
|
||||
</configuration>
|
||||
@@ -224,7 +249,6 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,11 @@
|
||||
package examples;
|
||||
|
||||
import net.schmizz.sshj.SSHClient;
|
||||
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
/**
|
||||
* This example demonstrates local port forwarding, i.e. when we listen on a particular address and port; and forward
|
||||
@@ -41,8 +43,16 @@ public class LocalPF {
|
||||
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
|
||||
* google.com:80
|
||||
*/
|
||||
ssh.newLocalPortForwarder(new InetSocketAddress("localhost", 8080), "google.com", 80)
|
||||
.listen();
|
||||
final LocalPortForwarder.Parameters params
|
||||
= new LocalPortForwarder.Parameters("0.0.0.0", 8080, "google.com", 80);
|
||||
final ServerSocket ss = new ServerSocket();
|
||||
ss.setReuseAddress(true);
|
||||
ss.bind(new InetSocketAddress(params.getLocalHost(), params.getLocalPort()));
|
||||
try {
|
||||
ssh.newLocalPortForwarder(params, ss).listen();
|
||||
} finally {
|
||||
ss.close();
|
||||
}
|
||||
|
||||
} finally {
|
||||
ssh.disconnect();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,12 +30,12 @@ public class ErrorDeliveryUtil {
|
||||
}
|
||||
|
||||
public static void alertEvents(Throwable x, Event... events) {
|
||||
for (Event e: events)
|
||||
for (Event e : events)
|
||||
e.deliverError(x);
|
||||
}
|
||||
|
||||
public static void alertEvents(Throwable x, Collection<? extends Event> events) {
|
||||
for (Event e: events)
|
||||
for (Event e : events)
|
||||
e.deliverError(x);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,8 +73,8 @@ public class Event<T extends Throwable> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this event is in a 'set' state. An event is set by a call to {@link set()} or {@link
|
||||
* deliverError}
|
||||
* @return whether this event is in a 'set' state. An event is set by a call to {@link #set} or {@link
|
||||
* #deliverError}
|
||||
*/
|
||||
public boolean isSet() {
|
||||
return promise.isDelivered();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,11 +162,14 @@ public class Promise<V, T extends Throwable> {
|
||||
if (val != null)
|
||||
return val;
|
||||
log.debug("Awaiting <<{}>>", name);
|
||||
while (val == null && pendingEx == null)
|
||||
if (timeout == 0)
|
||||
if (timeout == 0) {
|
||||
while (val == null && pendingEx == null) {
|
||||
cond.await();
|
||||
else if (!cond.await(timeout, unit))
|
||||
}
|
||||
} else {
|
||||
if (!cond.await(timeout, unit))
|
||||
return null;
|
||||
}
|
||||
if (pendingEx != null) {
|
||||
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
|
||||
throw pendingEx;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,13 +35,10 @@ public abstract class AbstractService
|
||||
protected final String name;
|
||||
/** Transport layer */
|
||||
protected final Transport trans;
|
||||
/** Timeout for blocking operations */
|
||||
protected int timeout;
|
||||
|
||||
public AbstractService(String name, Transport trans) {
|
||||
this.name = name;
|
||||
this.trans = trans;
|
||||
timeout = trans.getTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,12 +74,6 @@ public abstract class AbstractService
|
||||
trans.reqService(this);
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,8 @@ package net.schmizz.sshj;
|
||||
import net.schmizz.sshj.transport.random.JCERandom;
|
||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||
|
||||
public class AndroidConfig extends DefaultConfig {
|
||||
public class AndroidConfig
|
||||
extends DefaultConfig {
|
||||
|
||||
@Override
|
||||
protected void initRandomFactory(boolean ignored) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import java.util.List;
|
||||
* {@link Compression}, {@link MAC}, {@link Signature}, {@link Random}, and {@link FileKeyProvider}.
|
||||
*/
|
||||
public interface Config {
|
||||
|
||||
/**
|
||||
* Retrieve the list of named factories for {@code Cipher}.
|
||||
*
|
||||
@@ -53,16 +54,16 @@ public interface Config {
|
||||
List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories();
|
||||
|
||||
/**
|
||||
* Retrieve the list of named factories for <code>KeyExchange</code>.
|
||||
* Retrieve the list of named factories for {@code KeyExchange}.
|
||||
*
|
||||
* @return a list of named <code>KeyExchange</code> factories
|
||||
* @return a list of named {@code KeyExchange} factories
|
||||
*/
|
||||
List<Factory.Named<KeyExchange>> getKeyExchangeFactories();
|
||||
|
||||
/**
|
||||
* Retrieve the list of named factories for <code>MAC</code>.
|
||||
* Retrieve the list of named factories for {@code MAC}.
|
||||
*
|
||||
* @return a list of named <code>MAC</code> factories
|
||||
* @return a list of named {@code MAC} factories
|
||||
*/
|
||||
List<Factory.Named<MAC>> getMACFactories();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,15 +73,20 @@ import java.util.List;
|
||||
* A {@link Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
||||
* BouncyCastle is in the classpath.
|
||||
* <p/>
|
||||
* <ul> <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li> <li>{@link
|
||||
* ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR}, {@link
|
||||
* <ul>
|
||||
* <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li>
|
||||
* <li>{@link ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR},
|
||||
* {@link
|
||||
* AES128CBC}, {@link AES192CBC}, {@link AES256CBC}, {@link AES192CBC}, {@link TripleDESCBC}, {@link BlowfishCBC}</li>
|
||||
* <li>{@link ConfigImpl#setMACFactories MAC}: {@link HMACSHA1}, {@link HMACSHA196}, {@link HMACMD5}, {@link
|
||||
* HMACMD596}</li> <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li> <li>{@link
|
||||
* ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li> <li>{@link
|
||||
* ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li> <li>{@link
|
||||
* ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link OpenSSHKeyFile}*</li>
|
||||
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li> </ul>
|
||||
* HMACMD596}</li>
|
||||
* <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li>
|
||||
* <li>{@link ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li>
|
||||
* <li>{@link ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li>
|
||||
* <li>{@link ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link
|
||||
* OpenSSHKeyFile}*</li>
|
||||
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>
|
||||
* </ul>
|
||||
* <p/>
|
||||
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
||||
* prevents using ciphers with strength greater than 128.
|
||||
@@ -91,7 +96,7 @@ public class DefaultConfig
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static final String VERSION = "SSHJ_0_3";
|
||||
private static final String VERSION = "SSHJ_0_9_0";
|
||||
|
||||
public DefaultConfig() {
|
||||
setVersion(VERSION);
|
||||
@@ -113,7 +118,8 @@ public class DefaultConfig
|
||||
}
|
||||
|
||||
protected void initRandomFactory(boolean bouncyCastleRegistered) {
|
||||
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered ? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
|
||||
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered
|
||||
? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
|
||||
}
|
||||
|
||||
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
||||
@@ -137,7 +143,7 @@ public class DefaultConfig
|
||||
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();) {
|
||||
for (Iterator<Factory.Named<Cipher>> i = avail.iterator(); i.hasNext(); ) {
|
||||
final Factory.Named<Cipher> f = i.next();
|
||||
try {
|
||||
final Cipher c = f.create();
|
||||
@@ -161,7 +167,7 @@ public class DefaultConfig
|
||||
|
||||
protected void initMACFactories() {
|
||||
setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
|
||||
new HMACMD596.Factory());
|
||||
new HMACMD596.Factory());
|
||||
}
|
||||
|
||||
protected void initCompressionFactories() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package net.schmizz.sshj;
|
||||
|
||||
import net.schmizz.sshj.common.DisconnectReason;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
@@ -62,12 +61,14 @@ import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -92,8 +93,8 @@ import java.util.List;
|
||||
* <em>A simple example:</em>
|
||||
* <p/>
|
||||
* <pre>
|
||||
* client = new SSHClient();
|
||||
* client.initUserKnownHosts();
|
||||
* final SSHClient client = new SSHClient();
|
||||
* client.loadKnownHosts();
|
||||
* client.connect("hostname");
|
||||
* try {
|
||||
* client.authPassword("username", "password");
|
||||
@@ -103,8 +104,9 @@ import java.util.List;
|
||||
* cmd.join(1, TimeUnit.SECONDS);
|
||||
* } finally {
|
||||
* session.close();
|
||||
* } finally {
|
||||
* client.disconnect();
|
||||
* }
|
||||
* } finally {
|
||||
* client.disconnect();
|
||||
* }
|
||||
* </pre>
|
||||
* <p/>
|
||||
@@ -113,7 +115,7 @@ import java.util.List;
|
||||
*/
|
||||
public class SSHClient
|
||||
extends SocketClient
|
||||
implements SessionFactory {
|
||||
implements Closeable, SessionFactory {
|
||||
|
||||
/** Default port for SSH */
|
||||
public static final int DEFAULT_PORT = 22;
|
||||
@@ -174,6 +176,8 @@ public class SSHClient
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: there are way too many auth... overrides. Better API needed.
|
||||
|
||||
/**
|
||||
* Authenticate {@code username} using the supplied {@code methods}.
|
||||
*
|
||||
@@ -185,7 +189,7 @@ public class SSHClient
|
||||
*/
|
||||
public void auth(String username, AuthMethod... methods)
|
||||
throws UserAuthException, TransportException {
|
||||
assert isConnected();
|
||||
checkConnected();
|
||||
auth(username, Arrays.<AuthMethod>asList(methods));
|
||||
}
|
||||
|
||||
@@ -200,8 +204,17 @@ public class SSHClient
|
||||
*/
|
||||
public void auth(String username, Iterable<AuthMethod> methods)
|
||||
throws UserAuthException, TransportException {
|
||||
assert isConnected();
|
||||
auth.authenticate(username, (Service) conn, methods);
|
||||
checkConnected();
|
||||
final Deque<UserAuthException> savedEx = new LinkedList<UserAuthException>();
|
||||
for (AuthMethod method: methods) {
|
||||
try {
|
||||
if (auth.authenticate(username, (Service) conn, method, trans.getTimeoutMs()))
|
||||
return;
|
||||
} catch (UserAuthException e) {
|
||||
savedEx.push(e);
|
||||
}
|
||||
}
|
||||
throw new UserAuthException("Exhausted available authentication methods", savedEx.peek());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,8 +309,7 @@ public class SSHClient
|
||||
* @throws TransportException if there was a transport-layer error
|
||||
*/
|
||||
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
||||
throws UserAuthException,
|
||||
TransportException {
|
||||
throws UserAuthException, TransportException {
|
||||
final List<AuthMethod> am = new LinkedList<AuthMethod>();
|
||||
for (KeyProvider kp : keyProviders)
|
||||
am.add(new AuthPublickey(kp));
|
||||
@@ -342,13 +354,14 @@ public class SSHClient
|
||||
public void authPublickey(String username, String... locations)
|
||||
throws UserAuthException, TransportException {
|
||||
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
||||
for (String loc : locations)
|
||||
for (String loc : locations) {
|
||||
try {
|
||||
log.debug("Attempting to load key from: {}", loc);
|
||||
keyProviders.add(loadKeys(loc));
|
||||
} catch (IOException logged) {
|
||||
log.warn("Could not load keys due to: {}", logged);
|
||||
log.info("Could not load keys from {} due to: {}", loc, logged.getMessage());
|
||||
}
|
||||
}
|
||||
authPublickey(username, keyProviders);
|
||||
}
|
||||
|
||||
@@ -362,10 +375,8 @@ public class SSHClient
|
||||
@Override
|
||||
public void disconnect()
|
||||
throws IOException {
|
||||
assert isConnected();
|
||||
trans.disconnect();
|
||||
super.disconnect();
|
||||
assert !isConnected();
|
||||
}
|
||||
|
||||
/** @return the associated {@link Connection} instance. */
|
||||
@@ -391,8 +402,7 @@ public class SSHClient
|
||||
/**
|
||||
* @return the associated {@link UserAuth} instance. This allows access to information like the {@link
|
||||
* UserAuth#getBanner() authentication banner}, whether authentication was at least {@link
|
||||
* UserAuth#hadPartialSuccess() partially successful}, and any {@link UserAuth#getSavedExceptions() saved
|
||||
* exceptions} that were ignored because there were more authentication method that could be tried.
|
||||
* UserAuth#hadPartialSuccess() partially successful}.
|
||||
*/
|
||||
public UserAuth getUserAuth() {
|
||||
return auth;
|
||||
@@ -441,7 +451,7 @@ public class SSHClient
|
||||
/**
|
||||
* Utility function for createing a {@link KeyProvider} instance from given location on the file system. Creates a
|
||||
* one-off {@link PasswordFinder} using {@link PasswordUtils#createOneOff(char[])}, and calls {@link
|
||||
* #loadKeys(String,PasswordFinder)}.
|
||||
* #loadKeys(String, PasswordFinder)}.
|
||||
*
|
||||
* @param location location of the key file
|
||||
* @param passphrase passphrase as a char-array
|
||||
@@ -476,8 +486,8 @@ public class SSHClient
|
||||
throws IOException {
|
||||
final File loc = new File(location);
|
||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
|
||||
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
||||
.toString());
|
||||
final FileKeyProvider fkp =
|
||||
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||
if (fkp == null)
|
||||
throw new SSHException("No provider available for " + format + " key file");
|
||||
fkp.init(loc, passwordFinder);
|
||||
@@ -501,6 +511,33 @@ public class SSHClient
|
||||
return loadKeys(location, passphrase.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link KeyProvider} instance from passed strings. Currently only PKCS8 format private key files are
|
||||
* supported (OpenSSH uses this format).
|
||||
* <p/>
|
||||
*
|
||||
* @param privateKey the private key as a string
|
||||
* @param publicKey the public key as a string if it's not included with the private key
|
||||
* @param passwordFinder the {@link PasswordFinder} that can supply the passphrase for decryption (may be {@code
|
||||
* null} in case keyfile is not encrypted)
|
||||
*
|
||||
* @return the key provider ready for use in authentication
|
||||
*
|
||||
* @throws SSHException if there was no suitable key provider available for the file format; typically because
|
||||
* BouncyCastle is not in the classpath
|
||||
* @throws IOException if the key file format is not known, etc.
|
||||
*/
|
||||
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
|
||||
throws IOException {
|
||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
|
||||
final FileKeyProvider fkp =
|
||||
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||
if (fkp == null)
|
||||
throw new SSHException("No provider available for " + format + " key file");
|
||||
fkp.init(privateKey, publicKey, passwordFinder);
|
||||
return fkp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts loading the user's {@code known_hosts} file from the default locations, i.e. {@code ~/.ssh/known_hosts}
|
||||
* and {@code ~/.ssh/known_hosts2} on most platforms. Adds the resulting {@link OpenSSHKnownHosts} object as a host
|
||||
@@ -541,23 +578,21 @@ public class SSHClient
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link LocalPortForwarder} that will listen on {@code address} and forward incoming connections to the
|
||||
* server; which will further forward them to {@code host:port}.
|
||||
* Create a {@link LocalPortForwarder} that will listen based on {@code parameters} using the bound
|
||||
* {@code serverSocket} and forward incoming connections to the server; which will further forward them to
|
||||
* {@code host:port}.
|
||||
* <p/>
|
||||
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
||||
* listening, this method just creates an instance.
|
||||
*
|
||||
* @param address defines where the {@link LocalPortForwarder} listens
|
||||
* @param host hostname to which the server will forward
|
||||
* @param port the port at {@code hostname} to which the server wil forward
|
||||
* @param parameters parameters for the forwarding setup
|
||||
* @param serverSocket bound server socket
|
||||
*
|
||||
* @return a {@link LocalPortForwarder}
|
||||
*
|
||||
* @throws IOException if there is an error opening a local server socket
|
||||
*/
|
||||
public LocalPortForwarder newLocalPortForwarder(SocketAddress address, String host, int port)
|
||||
throws IOException {
|
||||
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
|
||||
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
|
||||
ServerSocket serverSocket) {
|
||||
return new LocalPortForwarder(conn, parameters, serverSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +617,8 @@ public class SSHClient
|
||||
|
||||
/** @return Instantiated {@link SCPFileTransfer} implementation. */
|
||||
public SCPFileTransfer newSCPFileTransfer() {
|
||||
assert isConnected() && isAuthenticated();
|
||||
checkConnected();
|
||||
checkAuthenticated();
|
||||
return new SCPFileTransfer(this);
|
||||
}
|
||||
|
||||
@@ -594,7 +630,8 @@ public class SSHClient
|
||||
*/
|
||||
public SFTPClient newSFTPClient()
|
||||
throws IOException {
|
||||
assert isConnected() && isAuthenticated();
|
||||
checkConnected();
|
||||
checkAuthenticated();
|
||||
return new SFTPClient(new SFTPEngine(this).init());
|
||||
}
|
||||
|
||||
@@ -611,10 +648,10 @@ public class SSHClient
|
||||
@Override
|
||||
public Session startSession()
|
||||
throws ConnectionException, TransportException {
|
||||
assert isConnected() && isAuthenticated();
|
||||
checkConnected();
|
||||
checkAuthenticated();
|
||||
final SessionChannel sess = new SessionChannel(conn);
|
||||
sess.open();
|
||||
assert sess.isOpen();
|
||||
return sess;
|
||||
}
|
||||
|
||||
@@ -654,11 +691,33 @@ public class SSHClient
|
||||
*/
|
||||
protected void doKex()
|
||||
throws TransportException {
|
||||
assert trans.isRunning();
|
||||
|
||||
checkConnected();
|
||||
final long start = System.currentTimeMillis();
|
||||
trans.doKex();
|
||||
log.info("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
||||
log.debug("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #disconnect()}.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
private void checkConnected() {
|
||||
if (!isConnected()) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAuthenticated() {
|
||||
if (!isAuthenticated()) {
|
||||
throw new IllegalStateException("Not authenticated");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,7 +35,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj;
|
||||
|
||||
import javax.net.ServerSocketFactory;
|
||||
import javax.net.SocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -44,8 +43,7 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
|
||||
abstract class SocketClient {
|
||||
public abstract class SocketClient {
|
||||
|
||||
private final int defaultPort;
|
||||
|
||||
@@ -54,7 +52,6 @@ abstract class SocketClient {
|
||||
private OutputStream output;
|
||||
|
||||
private SocketFactory socketFactory = SocketFactory.getDefault();
|
||||
private ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault();
|
||||
|
||||
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
||||
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
@@ -158,17 +155,6 @@ abstract class SocketClient {
|
||||
return socketFactory;
|
||||
}
|
||||
|
||||
public void setServerSocketFactory(ServerSocketFactory factory) {
|
||||
if (factory == null)
|
||||
serverSocketFactory = ServerSocketFactory.getDefault();
|
||||
else
|
||||
serverSocketFactory = factory;
|
||||
}
|
||||
|
||||
public ServerSocketFactory getServerSocketFactory() {
|
||||
return serverSocketFactory;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ public class Base64 {
|
||||
* @see Base64
|
||||
* @since 1.3
|
||||
*/
|
||||
public static class InputStream extends java.io.FilterInputStream {
|
||||
public static class InputStream
|
||||
extends java.io.FilterInputStream {
|
||||
|
||||
private final boolean encode; // Encoding or decoding
|
||||
private int position; // Current position in the buffer
|
||||
@@ -99,7 +100,8 @@ public class Base64 {
|
||||
* @since 1.3
|
||||
*/
|
||||
@Override
|
||||
public int read() throws java.io.IOException {
|
||||
public int read()
|
||||
throws java.io.IOException {
|
||||
|
||||
// Do we need to get data?
|
||||
if (position < 0)
|
||||
@@ -197,7 +199,8 @@ public class Base64 {
|
||||
* @since 1.3
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] dest, int off, int len) throws java.io.IOException {
|
||||
public int read(byte[] dest, int off, int len)
|
||||
throws java.io.IOException {
|
||||
int i;
|
||||
int b;
|
||||
for (i = 0; i < len; i++) {
|
||||
@@ -222,7 +225,8 @@ public class Base64 {
|
||||
* @see Base64
|
||||
* @since 1.3
|
||||
*/
|
||||
public static class OutputStream extends java.io.FilterOutputStream {
|
||||
public static class OutputStream
|
||||
extends java.io.FilterOutputStream {
|
||||
|
||||
private final boolean encode;
|
||||
private int position;
|
||||
@@ -289,7 +293,8 @@ public class Base64 {
|
||||
* @since 1.3
|
||||
*/
|
||||
@Override
|
||||
public void close() throws java.io.IOException {
|
||||
public void close()
|
||||
throws java.io.IOException {
|
||||
// 1. Ensure that pending characters are written
|
||||
flush();
|
||||
|
||||
@@ -308,7 +313,8 @@ public class Base64 {
|
||||
* @since 2.3
|
||||
*/
|
||||
@Override
|
||||
public void flush() throws java.io.IOException {
|
||||
public void flush()
|
||||
throws java.io.IOException {
|
||||
flushBase64();
|
||||
super.flush();
|
||||
}
|
||||
@@ -318,7 +324,8 @@ public class Base64 {
|
||||
*
|
||||
* @throws java.io.IOException if there's an error.
|
||||
*/
|
||||
public void flushBase64() throws java.io.IOException {
|
||||
public void flushBase64()
|
||||
throws java.io.IOException {
|
||||
if (position > 0)
|
||||
if (encode) {
|
||||
out.write(encode3to4(b4, buffer, position, options));
|
||||
@@ -346,7 +353,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there's an error flushing
|
||||
* @since 1.5.1
|
||||
*/
|
||||
public void suspendEncoding() throws java.io.IOException {
|
||||
public void suspendEncoding()
|
||||
throws java.io.IOException {
|
||||
flushBase64();
|
||||
suspendEncoding = true;
|
||||
} // end suspendEncoding
|
||||
@@ -361,7 +369,8 @@ public class Base64 {
|
||||
* @since 1.3
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] theBytes, int off, int len) throws java.io.IOException {
|
||||
public void write(byte[] theBytes, int off, int len)
|
||||
throws java.io.IOException {
|
||||
// Encoding suspended?
|
||||
if (suspendEncoding) {
|
||||
super.out.write(theBytes, off, len);
|
||||
@@ -383,7 +392,8 @@ public class Base64 {
|
||||
* @since 1.3
|
||||
*/
|
||||
@Override
|
||||
public void write(int theByte) throws java.io.IOException {
|
||||
public void write(int theByte)
|
||||
throws java.io.IOException {
|
||||
// Encoding suspended?
|
||||
if (suspendEncoding) {
|
||||
super.out.write(theByte);
|
||||
@@ -673,7 +683,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException If bogus characters exist in source data
|
||||
* @since 1.3
|
||||
*/
|
||||
public static byte[] decode(byte[] source, int off, int len, int options) throws java.io.IOException {
|
||||
public static byte[] decode(byte[] source, int off, int len, int options)
|
||||
throws java.io.IOException {
|
||||
|
||||
// Lots of error checking and exception throwing
|
||||
if (source == null)
|
||||
@@ -725,7 +736,7 @@ public class Base64 {
|
||||
else
|
||||
// There's a bad input character in the Base64 stream.
|
||||
throw new java.io.IOException(String.format("Bad Base64 input character '%c' in array position %d",
|
||||
source[i], i));
|
||||
source[i], i));
|
||||
} // each input character
|
||||
|
||||
byte[] out = new byte[outBuffPosn];
|
||||
@@ -743,7 +754,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException If there is a problem
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] decode(String s) throws java.io.IOException {
|
||||
public static byte[] decode(String s)
|
||||
throws java.io.IOException {
|
||||
return decode(s, NO_OPTIONS);
|
||||
}
|
||||
|
||||
@@ -759,7 +771,8 @@ public class Base64 {
|
||||
* @throws NullPointerException if <tt>s</tt> is null
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] decode(String s, int options) throws java.io.IOException {
|
||||
public static byte[] decode(String s, int options)
|
||||
throws java.io.IOException {
|
||||
|
||||
if (s == null)
|
||||
throw new NullPointerException("Input string was null.");
|
||||
@@ -833,7 +846,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @since 2.2
|
||||
*/
|
||||
public static void decodeFileToFile(String infile, String outfile) throws java.io.IOException {
|
||||
public static void decodeFileToFile(String infile, String outfile)
|
||||
throws java.io.IOException {
|
||||
|
||||
byte[] decoded = Base64.decodeFromFile(infile);
|
||||
java.io.OutputStream out = null;
|
||||
@@ -864,7 +878,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @since 2.1
|
||||
*/
|
||||
public static byte[] decodeFromFile(String filename) throws java.io.IOException {
|
||||
public static byte[] decodeFromFile(String filename)
|
||||
throws java.io.IOException {
|
||||
|
||||
byte[] decodedData = null;
|
||||
Base64.InputStream bis = null;
|
||||
@@ -878,12 +893,12 @@ public class Base64 {
|
||||
// Check for size of file
|
||||
if (file.length() > Integer.MAX_VALUE)
|
||||
throw new java.io.IOException("File is too big for this convenience method (" + file.length()
|
||||
+ " bytes).");
|
||||
+ " bytes).");
|
||||
buffer = new byte[(int) file.length()];
|
||||
|
||||
// Open a stream
|
||||
bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
|
||||
Base64.DECODE);
|
||||
Base64.DECODE);
|
||||
|
||||
// Read until done
|
||||
while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
|
||||
@@ -918,7 +933,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @since 2.1
|
||||
*/
|
||||
public static void decodeToFile(String dataToDecode, String filename) throws java.io.IOException {
|
||||
public static void decodeToFile(String dataToDecode, String filename)
|
||||
throws java.io.IOException {
|
||||
|
||||
Base64.OutputStream bos = null;
|
||||
try {
|
||||
@@ -950,8 +966,9 @@ public class Base64 {
|
||||
* @throws ClassNotFoundException if the decoded object is of a class that cannot be found by the JVM
|
||||
* @since 1.5
|
||||
*/
|
||||
public static Object decodeToObject(String encodedObject) throws java.io.IOException,
|
||||
java.lang.ClassNotFoundException {
|
||||
public static Object decodeToObject(String encodedObject)
|
||||
throws java.io.IOException,
|
||||
java.lang.ClassNotFoundException {
|
||||
|
||||
// Decode and gunzip if necessary
|
||||
byte[] objBytes = decode(encodedObject);
|
||||
@@ -1078,7 +1095,8 @@ public class Base64 {
|
||||
* @see Base64#DO_BREAK_LINES
|
||||
* @since 2.0
|
||||
*/
|
||||
public static String encodeBytes(byte[] source, int options) throws java.io.IOException {
|
||||
public static String encodeBytes(byte[] source, int options)
|
||||
throws java.io.IOException {
|
||||
return encodeBytes(source, 0, source.length, options);
|
||||
} // end encodeBytes
|
||||
|
||||
@@ -1137,7 +1155,8 @@ public class Base64 {
|
||||
* @see Base64#DO_BREAK_LINES
|
||||
* @since 2.0
|
||||
*/
|
||||
public static String encodeBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
|
||||
public static String encodeBytes(byte[] source, int off, int len, int options)
|
||||
throws java.io.IOException {
|
||||
byte[] encoded = encodeBytesToBytes(source, off, len, options);
|
||||
|
||||
// Return value according to relevant encoding.
|
||||
@@ -1189,7 +1208,8 @@ public class Base64 {
|
||||
* @see Base64#DO_BREAK_LINES
|
||||
* @since 2.3.1
|
||||
*/
|
||||
public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
|
||||
public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options)
|
||||
throws java.io.IOException {
|
||||
|
||||
if (source == null)
|
||||
throw new NullPointerException("Cannot serialize a null array.");
|
||||
@@ -1302,7 +1322,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @since 2.2
|
||||
*/
|
||||
public static void encodeFileToFile(String infile, String outfile) throws java.io.IOException {
|
||||
public static void encodeFileToFile(String infile, String outfile)
|
||||
throws java.io.IOException {
|
||||
|
||||
String encoded = Base64.encodeFromFile(infile);
|
||||
java.io.OutputStream out = null;
|
||||
@@ -1333,7 +1354,8 @@ public class Base64 {
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String encodeFromFile(String filename) throws java.io.IOException {
|
||||
public static String encodeFromFile(String filename)
|
||||
throws java.io.IOException {
|
||||
|
||||
String encodedData = null;
|
||||
Base64.InputStream bis = null;
|
||||
@@ -1348,7 +1370,7 @@ public class Base64 {
|
||||
|
||||
// Open a stream
|
||||
bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
|
||||
Base64.ENCODE);
|
||||
Base64.ENCODE);
|
||||
|
||||
// Read until done
|
||||
while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
|
||||
@@ -1387,7 +1409,8 @@ public class Base64 {
|
||||
* @throws NullPointerException if serializedObject is null
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String encodeObject(java.io.Serializable serializableObject) throws java.io.IOException {
|
||||
public static String encodeObject(java.io.Serializable serializableObject)
|
||||
throws java.io.IOException {
|
||||
return encodeObject(serializableObject, NO_OPTIONS);
|
||||
} // end encodeObject
|
||||
|
||||
@@ -1420,7 +1443,8 @@ public class Base64 {
|
||||
* @see Base64#DO_BREAK_LINES
|
||||
* @since 2.0
|
||||
*/
|
||||
public static String encodeObject(java.io.Serializable serializableObject, int options) throws java.io.IOException {
|
||||
public static String encodeObject(java.io.Serializable serializableObject, int options)
|
||||
throws java.io.IOException {
|
||||
|
||||
if (serializableObject == null)
|
||||
throw new NullPointerException("Cannot serialize a null object.");
|
||||
@@ -1481,7 +1505,8 @@ public class Base64 {
|
||||
* @throws NullPointerException if dataToEncode is null
|
||||
* @since 2.1
|
||||
*/
|
||||
public static void encodeToFile(byte[] dataToEncode, String filename) throws java.io.IOException {
|
||||
public static void encodeToFile(byte[] dataToEncode, String filename)
|
||||
throws java.io.IOException {
|
||||
|
||||
if (dataToEncode == null)
|
||||
throw new NullPointerException("Data to encode was null.");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,7 +51,7 @@ public class Buffer<T extends Buffer<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlainBuffer
|
||||
public static final class PlainBuffer
|
||||
extends Buffer<PlainBuffer> {
|
||||
|
||||
public PlainBuffer() {
|
||||
@@ -74,10 +74,15 @@ public class Buffer<T extends Buffer<T>> {
|
||||
/** The default size for a {@code Buffer} (256 bytes) */
|
||||
public static final int DEFAULT_SIZE = 256;
|
||||
|
||||
/** The maximum valid size of buffer (i.e. biggest power of two that can be represented as an int - 2^30) */
|
||||
public static final int MAX_SIZE = (1 << 30);
|
||||
|
||||
protected static int getNextPowerOf2(int i) {
|
||||
int j = 1;
|
||||
while (j < i)
|
||||
while (j < i) {
|
||||
j <<= 1;
|
||||
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
@@ -341,41 +346,13 @@ public class Buffer<T extends Buffer<T>> {
|
||||
*/
|
||||
public BigInteger readMPInt()
|
||||
throws BufferException {
|
||||
return new BigInteger(readMPIntAsBytes());
|
||||
return new BigInteger(readBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an SSH multiple-precision integer from a {@code BigInteger}
|
||||
*
|
||||
* @param bi {@code BigInteger} to write
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public T putMPInt(BigInteger bi) {
|
||||
return putMPInt(bi.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an SSH multiple-precision integer from a Java byte-array
|
||||
*
|
||||
* @param foo byte-array
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public T putMPInt(byte[] foo) {
|
||||
int i = foo.length;
|
||||
if ((foo[0] & 0x80) != 0) {
|
||||
i++;
|
||||
putUInt32(i);
|
||||
putByte((byte) 0);
|
||||
} else
|
||||
putUInt32(i);
|
||||
return putRawBytes(foo);
|
||||
}
|
||||
|
||||
public byte[] readMPIntAsBytes()
|
||||
throws BufferException {
|
||||
return readBytes();
|
||||
final byte[] asBytes = bi.toByteArray();
|
||||
putUInt32(asBytes.length);
|
||||
return putRawBytes(asBytes);
|
||||
}
|
||||
|
||||
public long readUInt64()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,25 +35,11 @@
|
||||
*/
|
||||
package net.schmizz.sshj.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/** Utility functions for byte arrays. */
|
||||
public class ByteArrayUtils {
|
||||
|
||||
final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
/**
|
||||
* Check whether two byte arrays are the equal.
|
||||
*
|
||||
* @param a1
|
||||
* @param a2
|
||||
*
|
||||
* @return <code>true</code> or <code>false</code>
|
||||
*/
|
||||
public static boolean equals(byte[] a1, byte[] a2) {
|
||||
return (a1.length != a2.length && equals(a1, 0, a2, 0, a1.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether some part or whole of two byte arrays is equal, for <code>length</code> bytes starting at some
|
||||
* offset.
|
||||
@@ -75,17 +61,6 @@ public class ByteArrayUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a hexadecimal representation of <code>array</code>, with each octet separated by a space.
|
||||
*
|
||||
* @param array
|
||||
*
|
||||
* @return hex string, each octet delimited by a space
|
||||
*/
|
||||
public static String printHex(byte[] array) {
|
||||
return printHex(array, 0, array.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a hexadecimal representation of a byte array starting at <code>offset</code> index for <code>len</code>
|
||||
* bytes, with each octet separated by a space.
|
||||
@@ -139,8 +114,4 @@ public class ByteArrayUtils {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] copyOf(byte[] array) {
|
||||
return Arrays.copyOf(array, array.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ public interface ErrorNotifiable {
|
||||
|
||||
/** Utility functions. */
|
||||
class Util {
|
||||
|
||||
/** Notify all {@code notifiables} of given {@code error}. */
|
||||
public static void alertAll(SSHException error, ErrorNotifiable... notifiables) {
|
||||
for (ErrorNotifiable notifiable : notifiables)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,6 @@ public enum KeyType {
|
||||
|
||||
/** SSH identifier for RSA keys */
|
||||
RSA("ssh-rsa") {
|
||||
|
||||
@Override
|
||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
||||
throws GeneralSecurityException {
|
||||
@@ -64,7 +63,6 @@ public enum KeyType {
|
||||
|
||||
/** SSH identifier for DSA keys */
|
||||
DSA("ssh-dss") {
|
||||
|
||||
@Override
|
||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
||||
throws GeneralSecurityException {
|
||||
@@ -100,7 +98,6 @@ public enum KeyType {
|
||||
|
||||
/** Unrecognized */
|
||||
UNKNOWN("unknown") {
|
||||
|
||||
@Override
|
||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
||||
throws GeneralSecurityException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ package net.schmizz.sshj.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SSHPacket
|
||||
public final class SSHPacket
|
||||
extends Buffer<SSHPacket> {
|
||||
|
||||
public SSHPacket() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,14 +58,15 @@ import java.security.Signature;
|
||||
public class SecurityUtils {
|
||||
|
||||
private static class BouncyCastleRegistration {
|
||||
|
||||
public void run()
|
||||
throws Exception {
|
||||
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
||||
LOG.info("Trying to register BouncyCastle as a JCE provider");
|
||||
LOG.debug("Trying to register BouncyCastle as a JCE provider");
|
||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||
MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
|
||||
KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
|
||||
LOG.info("Registration succeeded");
|
||||
LOG.info("BouncyCastle registration succeeded");
|
||||
} else
|
||||
LOG.info("BouncyCastle already registered as a JCE provider");
|
||||
securityProvider = BOUNCY_CASTLE;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -107,7 +107,7 @@ public class StreamCopier {
|
||||
log.debug("Done copying from {}", in);
|
||||
doneEvent.set();
|
||||
} catch (IOException ioe) {
|
||||
log.error("In pipe from {} to {}: " + ioe.toString(), in, out);
|
||||
log.error("In pipe from {} to {}: {}", new Object[] { in, out, ioe });
|
||||
doneEvent.deliverError(ioe);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public class StreamCopier {
|
||||
|
||||
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
||||
final double sizeKiB = count / 1024.0;
|
||||
log.info(sizeKiB + " KiB transferred in {} seconds ({} KiB/s)", timeSeconds, (sizeKiB / timeSeconds));
|
||||
log.debug("{} KiB transferred in {} seconds ({} KiB/s)", new Object[] { sizeKiB, timeSeconds, (sizeKiB / timeSeconds) });
|
||||
|
||||
if (length != -1 && read == -1)
|
||||
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
|
||||
@@ -154,4 +154,4 @@ public class StreamCopier {
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,13 +89,13 @@ public interface Connection {
|
||||
* @param wantReply whether a reply is requested
|
||||
* @param specifics {@link SSHPacket} containing fields specific to the request
|
||||
*
|
||||
* @return a {@link net.schmizz.concurrent.Promise} for the reply data (in case {@code wantReply} is true) which allows waiting on the
|
||||
* reply, or {@code null} if a reply is not requested.
|
||||
* @return a {@link net.schmizz.concurrent.Promise} for the reply data (in case {@code wantReply} is true) which
|
||||
* allows waiting on the reply, or {@code null} if a reply is not requested.
|
||||
*
|
||||
* @throws TransportException if there is an error sending the request
|
||||
*/
|
||||
public Promise<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
|
||||
byte[] specifics)
|
||||
byte[] specifics)
|
||||
throws TransportException;
|
||||
|
||||
/**
|
||||
@@ -125,29 +125,29 @@ public interface Connection {
|
||||
void setMaxPacketSize(int maxPacketSize);
|
||||
|
||||
/** @return the size for the local window this connection recommends to any {@link Channel}'s that ask for it. */
|
||||
int getWindowSize();
|
||||
long getWindowSize();
|
||||
|
||||
/**
|
||||
* Set the size for the local window this connection recommends to any {@link Channel}'s that ask for it.
|
||||
*
|
||||
* @param windowSize window size in bytes
|
||||
*/
|
||||
void setWindowSize(int windowSize);
|
||||
void setWindowSize(long windowSize);
|
||||
|
||||
/** @return the associated {@link Transport}. */
|
||||
Transport getTransport();
|
||||
|
||||
/**
|
||||
* @return the {@code timeout} in seconds that this connection uses for blocking operations and recommends to any
|
||||
* {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
|
||||
* @return the {@code timeout} in milliseconds that this connection uses for blocking operations and recommends to
|
||||
* any {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
|
||||
*/
|
||||
int getTimeout();
|
||||
int getTimeoutMs();
|
||||
|
||||
/**
|
||||
* Set the {@code timeout} this connection uses for blocking operations and recommends to any {@link Channel other}
|
||||
* {@link ForwardedChannelOpener classes} that ask for it.
|
||||
*
|
||||
* @param timeout timeout in seconds
|
||||
* @param timeout timeout in milliseconds
|
||||
*/
|
||||
void setTimeout(int timeout);
|
||||
void setTimeoutMs(int timeout);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,9 +51,11 @@ public class ConnectionImpl
|
||||
|
||||
private final Queue<Promise<SSHPacket, ConnectionException>> globalReqPromises = new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
||||
|
||||
private int windowSize = 2048 * 1024;
|
||||
private long windowSize = 2048 * 1024;
|
||||
private int maxPacketSize = 32 * 1024;
|
||||
|
||||
private volatile int timeoutMs;
|
||||
|
||||
/**
|
||||
* Create with an associated {@link Transport}.
|
||||
*
|
||||
@@ -61,11 +63,12 @@ public class ConnectionImpl
|
||||
*/
|
||||
public ConnectionImpl(Transport trans) {
|
||||
super("ssh-connection", trans);
|
||||
timeoutMs = trans.getTimeoutMs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(Channel chan) {
|
||||
log.info("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
|
||||
log.debug("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
|
||||
channels.put(chan.getID(), chan);
|
||||
}
|
||||
|
||||
@@ -81,7 +84,7 @@ public class ConnectionImpl
|
||||
|
||||
@Override
|
||||
public void forget(Channel chan) {
|
||||
log.info("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
|
||||
log.debug("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
|
||||
channels.remove(chan.getID());
|
||||
synchronized (internalSynchronizer) {
|
||||
if (channels.isEmpty())
|
||||
@@ -91,13 +94,13 @@ public class ConnectionImpl
|
||||
|
||||
@Override
|
||||
public void forget(ForwardedChannelOpener opener) {
|
||||
log.info("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||
log.debug("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||
openers.remove(opener.getChannelType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(ForwardedChannelOpener opener) {
|
||||
log.info("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||
log.debug("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||
openers.put(opener.getChannelType(), opener);
|
||||
}
|
||||
|
||||
@@ -159,12 +162,12 @@ public class ConnectionImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWindowSize() {
|
||||
public long getWindowSize() {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowSize(int windowSize) {
|
||||
public void setWindowSize(long windowSize) {
|
||||
this.windowSize = windowSize;
|
||||
}
|
||||
|
||||
@@ -187,7 +190,7 @@ public class ConnectionImpl
|
||||
byte[] specifics)
|
||||
throws TransportException {
|
||||
synchronized (globalReqPromises) {
|
||||
log.info("Making global request for `{}`", name);
|
||||
log.debug("Making global request for `{}`", name);
|
||||
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
|
||||
.putBoolean(wantReply)
|
||||
.putRawBytes(specifics));
|
||||
@@ -251,4 +254,14 @@ public class ConnectionImpl
|
||||
channels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeoutMs(int timeoutMs) {
|
||||
this.timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeoutMs() {
|
||||
return timeoutMs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,8 +35,8 @@
|
||||
*/
|
||||
package net.schmizz.sshj.connection.channel;
|
||||
|
||||
import net.schmizz.concurrent.Event;
|
||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||
import net.schmizz.concurrent.Event;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.ByteArrayUtils;
|
||||
import net.schmizz.sshj.common.DisconnectReason;
|
||||
@@ -61,6 +61,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
public abstract class AbstractChannel
|
||||
implements Channel {
|
||||
|
||||
private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
|
||||
|
||||
/** Logger */
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -79,11 +81,11 @@ public abstract class AbstractChannel
|
||||
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
|
||||
|
||||
/* The lock used by to create the open & close events */
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final ReentrantLock openCloseLock = new ReentrantLock();
|
||||
/** Channel open event */
|
||||
protected final Event<ConnectionException> open;
|
||||
protected final Event<ConnectionException> openEvent;
|
||||
/** Channel close event */
|
||||
protected final Event<ConnectionException> close;
|
||||
protected final Event<ConnectionException> closeEvent;
|
||||
|
||||
/* Access to these fields should be synchronized using this object */
|
||||
private boolean eofSent;
|
||||
@@ -112,15 +114,15 @@ public abstract class AbstractChannel
|
||||
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
|
||||
in = new ChannelInputStream(this, trans, lwin);
|
||||
|
||||
open = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, lock);
|
||||
close = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, lock);
|
||||
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock);
|
||||
closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock);
|
||||
}
|
||||
|
||||
protected void init(int recipient, int remoteWinSize, int remoteMaxPacketSize) {
|
||||
protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) {
|
||||
this.recipient = recipient;
|
||||
rwin = new Window.Remote(remoteWinSize, remoteMaxPacketSize);
|
||||
rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING));
|
||||
out = new ChannelOutputStream(this, trans, rwin);
|
||||
log.info("Initialized - {}", this);
|
||||
log.debug("Initialized - {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,7 +146,7 @@ public abstract class AbstractChannel
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalWinSize() {
|
||||
public long getLocalWinSize() {
|
||||
return lwin.getSize();
|
||||
}
|
||||
|
||||
@@ -164,7 +166,7 @@ public abstract class AbstractChannel
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemoteWinSize() {
|
||||
public long getRemoteWinSize() {
|
||||
return rwin.getSize();
|
||||
}
|
||||
|
||||
@@ -218,7 +220,7 @@ public abstract class AbstractChannel
|
||||
|
||||
private void gotClose()
|
||||
throws TransportException {
|
||||
log.info("Got close");
|
||||
log.debug("Got close");
|
||||
try {
|
||||
closeAllStreams();
|
||||
sendClose();
|
||||
@@ -236,11 +238,12 @@ public abstract class AbstractChannel
|
||||
public void notifyError(SSHException error) {
|
||||
log.debug("Channel #{} got notified of {}", getID(), error.toString());
|
||||
|
||||
ErrorDeliveryUtil.alertEvents(error, open, close);
|
||||
ErrorDeliveryUtil.alertEvents(error, openEvent, closeEvent);
|
||||
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
|
||||
|
||||
in.notifyError(error);
|
||||
out.notifyError(error);
|
||||
if (out != null)
|
||||
out.notifyError(error);
|
||||
|
||||
finishOff();
|
||||
}
|
||||
@@ -253,35 +256,37 @@ public abstract class AbstractChannel
|
||||
@Override
|
||||
public void close()
|
||||
throws ConnectionException, TransportException {
|
||||
lock.lock();
|
||||
openCloseLock.lock();
|
||||
try {
|
||||
try {
|
||||
sendClose();
|
||||
} catch (TransportException e) {
|
||||
if (!close.inError())
|
||||
throw e;
|
||||
if (isOpen()) {
|
||||
try {
|
||||
sendClose();
|
||||
} catch (TransportException e) {
|
||||
if (!closeEvent.inError())
|
||||
throw e;
|
||||
}
|
||||
closeEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
close.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
openCloseLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void join()
|
||||
throws ConnectionException {
|
||||
close.await();
|
||||
closeEvent.await();
|
||||
}
|
||||
|
||||
public void join(int timeout, TimeUnit unit)
|
||||
throws ConnectionException {
|
||||
close.await(timeout, unit);
|
||||
closeEvent.await(timeout, unit);
|
||||
}
|
||||
|
||||
protected synchronized void sendClose()
|
||||
throws TransportException {
|
||||
try {
|
||||
if (!closeRequested) {
|
||||
log.info("Sending close");
|
||||
log.debug("Sending close");
|
||||
trans.write(newBuffer(Message.CHANNEL_CLOSE));
|
||||
}
|
||||
} finally {
|
||||
@@ -291,11 +296,11 @@ public abstract class AbstractChannel
|
||||
|
||||
@Override
|
||||
public synchronized boolean isOpen() {
|
||||
lock.lock();
|
||||
openCloseLock.lock();
|
||||
try {
|
||||
return open.isSet() && !close.isSet() && !closeRequested;
|
||||
return openEvent.isSet() && !closeEvent.isSet() && !closeRequested;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
openCloseLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,24 +313,25 @@ public abstract class AbstractChannel
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new ConnectionException(be);
|
||||
}
|
||||
log.info("Got chan request for `{}`", reqType);
|
||||
log.debug("Got chan request for `{}`", reqType);
|
||||
handleRequest(reqType, buf);
|
||||
}
|
||||
|
||||
private void gotWindowAdjustment(SSHPacket buf) throws ConnectionException {
|
||||
final int howMuch;
|
||||
private void gotWindowAdjustment(SSHPacket buf)
|
||||
throws ConnectionException {
|
||||
final long howMuch;
|
||||
try {
|
||||
howMuch = buf.readUInt32AsInt();
|
||||
howMuch = buf.readUInt32();
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new ConnectionException(be);
|
||||
}
|
||||
log.info("Received window adjustment for {} bytes", howMuch);
|
||||
log.debug("Received window adjustment for {} bytes", howMuch);
|
||||
rwin.expand(howMuch);
|
||||
}
|
||||
|
||||
protected void finishOff() {
|
||||
conn.forget(this);
|
||||
close.set();
|
||||
closeEvent.set();
|
||||
}
|
||||
|
||||
protected void gotExtendedData(SSHPacket buf)
|
||||
@@ -362,42 +368,46 @@ public abstract class AbstractChannel
|
||||
stream.receive(buf.array(), buf.rpos(), len);
|
||||
}
|
||||
|
||||
protected synchronized Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
||||
Buffer.PlainBuffer reqSpecific)
|
||||
protected Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
||||
Buffer.PlainBuffer reqSpecific)
|
||||
throws TransportException {
|
||||
log.info("Sending channel request for `{}`", reqType);
|
||||
trans.write(
|
||||
newBuffer(Message.CHANNEL_REQUEST)
|
||||
.putString(reqType)
|
||||
.putBoolean(wantReply)
|
||||
.putBuffer(reqSpecific)
|
||||
);
|
||||
log.debug("Sending channel request for `{}`", reqType);
|
||||
synchronized (chanReqResponseEvents) {
|
||||
trans.write(
|
||||
newBuffer(Message.CHANNEL_REQUEST)
|
||||
.putString(reqType)
|
||||
.putBoolean(wantReply)
|
||||
.putBuffer(reqSpecific)
|
||||
);
|
||||
|
||||
Event<ConnectionException> responseEvent = null;
|
||||
if (wantReply) {
|
||||
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType, ConnectionException.chainer, lock);
|
||||
chanReqResponseEvents.add(responseEvent);
|
||||
Event<ConnectionException> responseEvent = null;
|
||||
if (wantReply) {
|
||||
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
|
||||
ConnectionException.chainer);
|
||||
chanReqResponseEvents.add(responseEvent);
|
||||
}
|
||||
return responseEvent;
|
||||
}
|
||||
return responseEvent;
|
||||
}
|
||||
|
||||
private synchronized void gotResponse(boolean success)
|
||||
private void gotResponse(boolean success)
|
||||
throws ConnectionException {
|
||||
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
||||
if (responseEvent != null) {
|
||||
if (success)
|
||||
responseEvent.set();
|
||||
else
|
||||
responseEvent.deliverError(new ConnectionException("Request failed"));
|
||||
} else
|
||||
throw new ConnectionException(
|
||||
DisconnectReason.PROTOCOL_ERROR,
|
||||
"Received response to channel request when none was requested");
|
||||
synchronized (chanReqResponseEvents) {
|
||||
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
||||
if (responseEvent != null) {
|
||||
if (success)
|
||||
responseEvent.set();
|
||||
else
|
||||
responseEvent.deliverError(new ConnectionException("Request failed"));
|
||||
} else
|
||||
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
||||
"Received response to channel request when none was requested");
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void gotEOF()
|
||||
throws TransportException {
|
||||
log.info("Got EOF");
|
||||
log.debug("Got EOF");
|
||||
eofGot = true;
|
||||
eofInputStreams();
|
||||
if (eofSent)
|
||||
@@ -414,7 +424,7 @@ public abstract class AbstractChannel
|
||||
throws TransportException {
|
||||
try {
|
||||
if (!closeRequested && !eofSent) {
|
||||
log.info("Sending EOF");
|
||||
log.debug("Sending EOF");
|
||||
trans.write(newBuffer(Message.CHANNEL_EOF));
|
||||
if (eofGot)
|
||||
sendClose();
|
||||
@@ -428,7 +438,7 @@ public abstract class AbstractChannel
|
||||
@Override
|
||||
public String toString() {
|
||||
return "< " + type + " channel: id=" + id + ", recipient=" + recipient + ", localWin=" + lwin + ", remoteWin="
|
||||
+ rwin + " >";
|
||||
+ rwin + " >";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ public interface Channel
|
||||
/** Direct channels are those that are initiated by us. */
|
||||
interface Direct
|
||||
extends Channel {
|
||||
|
||||
/**
|
||||
* Request opening this channel from remote end.
|
||||
*
|
||||
@@ -98,7 +99,7 @@ public interface Channel
|
||||
int getLocalMaxPacketSize();
|
||||
|
||||
/** @return the current local window size. */
|
||||
int getLocalWinSize();
|
||||
long getLocalWinSize();
|
||||
|
||||
/** @return an {@code OutputStream} for this channel. */
|
||||
OutputStream getOutputStream();
|
||||
@@ -110,7 +111,7 @@ public interface Channel
|
||||
int getRemoteMaxPacketSize();
|
||||
|
||||
/** @return the current remote window size. */
|
||||
int getRemoteWinSize();
|
||||
long getRemoteWinSize();
|
||||
|
||||
/** @return the channel type identifier. */
|
||||
String getType();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -116,7 +116,7 @@ public final class ChannelInputStream
|
||||
public int read(byte[] b, int off, int len)
|
||||
throws IOException {
|
||||
synchronized (buf) {
|
||||
for (; ;) {
|
||||
for (; ; ) {
|
||||
if (buf.available() > 0)
|
||||
break;
|
||||
if (eof)
|
||||
@@ -159,11 +159,11 @@ public final class ChannelInputStream
|
||||
private void checkWindow()
|
||||
throws TransportException {
|
||||
synchronized (win) {
|
||||
final int adjustment = win.neededAdjustment();
|
||||
final long adjustment = win.neededAdjustment();
|
||||
if (adjustment > 0) {
|
||||
log.info("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
||||
log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
||||
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
|
||||
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
||||
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
||||
win.expand(adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,12 +35,14 @@
|
||||
*/
|
||||
package net.schmizz.sshj.connection.channel;
|
||||
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
||||
import net.schmizz.sshj.common.Message;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
import net.schmizz.sshj.connection.ConnectionException;
|
||||
import net.schmizz.sshj.transport.Transport;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -56,26 +58,92 @@ public final class ChannelOutputStream
|
||||
private final Channel chan;
|
||||
private final Transport trans;
|
||||
private final Window.Remote win;
|
||||
private final SSHPacket buffer = new SSHPacket();
|
||||
|
||||
private final DataBuffer buffer = new DataBuffer();
|
||||
private final byte[] b = new byte[1];
|
||||
private int bufferLength;
|
||||
|
||||
private boolean closed;
|
||||
private SSHException error;
|
||||
|
||||
private final class DataBuffer {
|
||||
|
||||
private final int headerOffset;
|
||||
private final int dataOffset;
|
||||
|
||||
private final SSHPacket packet = new SSHPacket(Message.CHANNEL_DATA);
|
||||
private final Buffer.PlainBuffer leftOvers = new Buffer.PlainBuffer();
|
||||
|
||||
DataBuffer() {
|
||||
headerOffset = packet.rpos();
|
||||
packet.putUInt32(0); // recipient
|
||||
packet.putUInt32(0); // data length
|
||||
dataOffset = packet.wpos();
|
||||
}
|
||||
|
||||
int write(byte[] data, int off, int len)
|
||||
throws TransportException, ConnectionException {
|
||||
final int bufferSize = packet.wpos() - dataOffset;
|
||||
if (bufferSize >= win.getMaxPacketSize()) {
|
||||
flush(bufferSize);
|
||||
return 0;
|
||||
} else {
|
||||
final int n = Math.min(len, win.getMaxPacketSize() - bufferSize);
|
||||
packet.putRawBytes(data, off, n);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
void flush()
|
||||
throws TransportException, ConnectionException {
|
||||
flush(packet.wpos() - dataOffset);
|
||||
}
|
||||
|
||||
void flush(int bufferSize)
|
||||
throws TransportException, ConnectionException {
|
||||
while (bufferSize > 0) {
|
||||
|
||||
long remoteWindowSize = win.getSize();
|
||||
if (remoteWindowSize == 0)
|
||||
remoteWindowSize = win.awaitExpansion(remoteWindowSize);
|
||||
|
||||
// We can only write the min. of
|
||||
// a) how much data we have
|
||||
// b) the max packet size
|
||||
// c) what the current window size will allow
|
||||
final int writeNow = Math.min(bufferSize, (int) Math.min(win.getMaxPacketSize(), remoteWindowSize));
|
||||
|
||||
packet.wpos(headerOffset);
|
||||
packet.putMessageID(Message.CHANNEL_DATA);
|
||||
packet.putUInt32(chan.getRecipient());
|
||||
packet.putUInt32(writeNow);
|
||||
packet.wpos(dataOffset + writeNow);
|
||||
|
||||
final int leftOverBytes = bufferSize - writeNow;
|
||||
if (leftOverBytes > 0) {
|
||||
leftOvers.putRawBytes(packet.array(), packet.wpos(), leftOverBytes);
|
||||
}
|
||||
|
||||
trans.write(packet);
|
||||
win.consume(writeNow);
|
||||
|
||||
packet.rpos(headerOffset);
|
||||
packet.wpos(dataOffset);
|
||||
|
||||
if (leftOverBytes > 0) {
|
||||
packet.putBuffer(leftOvers);
|
||||
leftOvers.clear();
|
||||
}
|
||||
|
||||
bufferSize = leftOverBytes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
|
||||
this.chan = chan;
|
||||
this.trans = trans;
|
||||
this.win = win;
|
||||
prepBuffer();
|
||||
}
|
||||
|
||||
private void prepBuffer() {
|
||||
bufferLength = 0;
|
||||
buffer.rpos(5);
|
||||
buffer.wpos(5);
|
||||
buffer.putMessageID(Message.CHANNEL_DATA);
|
||||
buffer.putUInt32(0); // meant to be recipient
|
||||
buffer.putUInt32(0); // meant to be data length
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,19 +154,13 @@ public final class ChannelOutputStream
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] data, int off, int len)
|
||||
public synchronized void write(final byte[] data, int off, int len)
|
||||
throws IOException {
|
||||
checkClose();
|
||||
while (len > 0) {
|
||||
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
|
||||
if (x <= 0) {
|
||||
flush();
|
||||
continue;
|
||||
}
|
||||
buffer.putRawBytes(data, off, x);
|
||||
bufferLength += x;
|
||||
off += x;
|
||||
len -= x;
|
||||
final int n = buffer.write(data, off, len);
|
||||
off += n;
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,55 +169,44 @@ public final class ChannelOutputStream
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
private synchronized void checkClose()
|
||||
private void checkClose()
|
||||
throws SSHException {
|
||||
if (closed)
|
||||
if (closed) {
|
||||
if (error != null)
|
||||
throw error;
|
||||
else
|
||||
throw new ConnectionException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close()
|
||||
throws IOException {
|
||||
if (!closed)
|
||||
if (!closed) {
|
||||
try {
|
||||
flush();
|
||||
buffer.flush();
|
||||
chan.sendEOF();
|
||||
} finally {
|
||||
setClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setClosed() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all data currently buffered. If window space is exhausted in the process, this will block
|
||||
* until it is expanded by the server.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public synchronized void flush()
|
||||
throws IOException {
|
||||
checkClose();
|
||||
|
||||
if (bufferLength <= 0) // No data to send
|
||||
return;
|
||||
|
||||
putRecipientAndLength();
|
||||
|
||||
try {
|
||||
win.waitAndConsume(bufferLength);
|
||||
trans.write(buffer);
|
||||
} finally {
|
||||
prepBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
private void putRecipientAndLength() {
|
||||
final int origPos = buffer.wpos();
|
||||
buffer.wpos(6);
|
||||
buffer.putUInt32(chan.getRecipient());
|
||||
buffer.putUInt32(bufferLength);
|
||||
buffer.wpos(origPos);
|
||||
buffer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,4 +214,4 @@ public final class ChannelOutputStream
|
||||
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,8 +43,8 @@ public class SocketStreamCopyMonitor
|
||||
}
|
||||
|
||||
public static void monitor(final int frequency, final TimeUnit unit,
|
||||
final Event<IOException> x, final Event<IOException> y,
|
||||
final Channel channel, final Socket socket) {
|
||||
final Event<IOException> x, final Event<IOException> y,
|
||||
final Channel channel, final Socket socket) {
|
||||
new SocketStreamCopyMonitor(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,17 +28,17 @@ public abstract class Window {
|
||||
|
||||
protected final int maxPacketSize;
|
||||
|
||||
protected int size;
|
||||
protected long size;
|
||||
|
||||
public Window(int initialWinSize, int maxPacketSize) {
|
||||
public Window(long initialWinSize, int maxPacketSize) {
|
||||
size = initialWinSize;
|
||||
this.maxPacketSize = maxPacketSize;
|
||||
}
|
||||
|
||||
public void expand(int inc) {
|
||||
public void expand(long inc) {
|
||||
synchronized (lock) {
|
||||
log.debug("Increasing by {} up to {}", inc, size);
|
||||
size += inc;
|
||||
log.debug("Increasing by {} up to {}", inc, size);
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
@@ -47,16 +47,19 @@ public abstract class Window {
|
||||
return maxPacketSize;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
public long getSize() {
|
||||
synchronized (lock) {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public void consume(int dec) {
|
||||
public void consume(long dec)
|
||||
throws ConnectionException {
|
||||
synchronized (lock) {
|
||||
log.debug("Consuming by " + dec + " down to " + size);
|
||||
size -= dec;
|
||||
log.debug("Consuming by {} down to {}", dec, size);
|
||||
if (size < 0)
|
||||
throw new SSHRuntimeException("Window consumed to below 0");
|
||||
throw new ConnectionException("Window consumed to below 0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,22 +72,30 @@ public abstract class Window {
|
||||
public static final class Remote
|
||||
extends Window {
|
||||
|
||||
public Remote(int initialWinSize, int maxPacketSize) {
|
||||
public Remote(long initialWinSize, int maxPacketSize) {
|
||||
super(initialWinSize, maxPacketSize);
|
||||
}
|
||||
|
||||
public void waitAndConsume(int howMuch)
|
||||
public long awaitExpansion(long was)
|
||||
throws ConnectionException {
|
||||
synchronized (lock) {
|
||||
while (size < howMuch) {
|
||||
log.debug("Waiting, need window space for {} bytes", howMuch);
|
||||
while (size <= was) {
|
||||
log.debug("Waiting, need size to grow from {} bytes", was);
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
throw new ConnectionException(ie);
|
||||
}
|
||||
}
|
||||
consume(howMuch);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public void consume(long howMuch) {
|
||||
try {
|
||||
super.consume(howMuch);
|
||||
} catch (ConnectionException e) { // It's a bug if we consume more than remote allowed
|
||||
throw new SSHRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,18 +105,18 @@ public abstract class Window {
|
||||
public static final class Local
|
||||
extends Window {
|
||||
|
||||
private final int initialSize;
|
||||
private final int threshold;
|
||||
private final long initialSize;
|
||||
private final long threshold;
|
||||
|
||||
public Local(int initialWinSize, int maxPacketSize) {
|
||||
public Local(long initialWinSize, int maxPacketSize) {
|
||||
super(initialWinSize, maxPacketSize);
|
||||
this.initialSize = initialWinSize;
|
||||
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
||||
}
|
||||
|
||||
public int neededAdjustment() {
|
||||
public long neededAdjustment() {
|
||||
synchronized (lock) {
|
||||
return (size - threshold <= 0) ? (initialSize - size) : 0;
|
||||
return (size <= threshold) ? (initialSize - size) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,23 +65,23 @@ public abstract class AbstractDirectChannel
|
||||
public void open()
|
||||
throws ConnectionException, TransportException {
|
||||
trans.write(buildOpenReq());
|
||||
open.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
openEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void gotOpenConfirmation(SSHPacket buf)
|
||||
throws ConnectionException {
|
||||
try {
|
||||
init(buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt());
|
||||
init(buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32());
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new ConnectionException(be);
|
||||
}
|
||||
open.set();
|
||||
openEvent.set();
|
||||
}
|
||||
|
||||
private void gotOpenFailure(SSHPacket buf)
|
||||
throws ConnectionException {
|
||||
try {
|
||||
open.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
||||
openEvent.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new ConnectionException(be);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,104 +19,104 @@ import net.schmizz.concurrent.Event;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
import net.schmizz.sshj.common.StreamCopier;
|
||||
import net.schmizz.sshj.connection.Connection;
|
||||
import net.schmizz.sshj.connection.ConnectionException;
|
||||
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ServerSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LocalPortForwarder {
|
||||
|
||||
private class DirectTCPIPChannel
|
||||
extends AbstractDirectChannel {
|
||||
public static class Parameters {
|
||||
|
||||
private final Socket sock;
|
||||
private final String localHost;
|
||||
private final int localPort;
|
||||
private final String remoteHost;
|
||||
private final int remotePort;
|
||||
|
||||
private DirectTCPIPChannel(Connection conn, Socket sock) {
|
||||
super(conn, "direct-tcpip");
|
||||
this.sock = sock;
|
||||
public Parameters(String localHost, int localPort, String remoteHost, int remotePort) {
|
||||
this.localHost = localHost;
|
||||
this.localPort = localPort;
|
||||
this.remoteHost = remoteHost;
|
||||
this.remotePort = remotePort;
|
||||
}
|
||||
|
||||
private void start()
|
||||
public String getRemoteHost() {
|
||||
return remoteHost;
|
||||
}
|
||||
|
||||
public int getRemotePort() {
|
||||
return remotePort;
|
||||
}
|
||||
|
||||
public String getLocalHost() {
|
||||
return localHost;
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
return localPort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DirectTCPIPChannel
|
||||
extends AbstractDirectChannel {
|
||||
|
||||
protected final Socket socket;
|
||||
protected final Parameters parameters;
|
||||
|
||||
public DirectTCPIPChannel(Connection conn, Socket socket, Parameters parameters) {
|
||||
super(conn, "direct-tcpip");
|
||||
this.socket = socket;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
protected void start()
|
||||
throws IOException {
|
||||
sock.setSendBufferSize(getLocalMaxPacketSize());
|
||||
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
|
||||
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), getOutputStream())
|
||||
socket.setSendBufferSize(getLocalMaxPacketSize());
|
||||
socket.setReceiveBufferSize(getRemoteMaxPacketSize());
|
||||
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream())
|
||||
.bufSize(getRemoteMaxPacketSize())
|
||||
.spawnDaemon("soc2chan");
|
||||
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), sock.getOutputStream())
|
||||
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream())
|
||||
.bufSize(getLocalMaxPacketSize())
|
||||
.spawnDaemon("chan2soc");
|
||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, sock);
|
||||
}
|
||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSHPacket buildOpenReq() {
|
||||
return super.buildOpenReq()
|
||||
.putString(host)
|
||||
.putUInt32(port)
|
||||
.putString(ss.getInetAddress().getHostAddress())
|
||||
.putUInt32(ss.getLocalPort());
|
||||
.putString(parameters.getRemoteHost())
|
||||
.putUInt32(parameters.getRemotePort())
|
||||
.putString(parameters.getLocalHost())
|
||||
.putUInt32(parameters.getLocalPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Logger log = LoggerFactory.getLogger(LocalPortForwarder.class);
|
||||
|
||||
private final Connection conn;
|
||||
private final ServerSocket ss;
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final Parameters parameters;
|
||||
private final ServerSocket serverSocket;
|
||||
|
||||
/**
|
||||
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
|
||||
* listening unless {@link #listen() explicitly told to}. The {@link javax.net.ServerSocketFactory#getDefault()
|
||||
* default} server socket factory is used.
|
||||
*
|
||||
* @param conn {@link Connection} implementation
|
||||
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
|
||||
* and valid local address will be picked to bind the server socket
|
||||
* @param host what host the SSH server will further forward to
|
||||
* @param port port on {@code toHost}
|
||||
*
|
||||
* @throws IOException if there is an error binding on specified {@code listeningAddr}
|
||||
*/
|
||||
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port)
|
||||
throws IOException {
|
||||
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
|
||||
* listening unless {@link #listen() explicitly told to}.
|
||||
*
|
||||
* @param ssf factory to use for creating the server socket
|
||||
* @param conn {@link Connection} implementation
|
||||
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
|
||||
* and valid local address will be picked to bind the server socket
|
||||
* @param host what host the SSH server will further forward to
|
||||
* @param port port on {@code toHost}
|
||||
*
|
||||
* @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(Connection conn, Parameters parameters, ServerSocket serverSocket) {
|
||||
this.conn = conn;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.ss = ssf.createServerSocket();
|
||||
ss.setReceiveBufferSize(conn.getMaxPacketSize());
|
||||
ss.bind(listeningAddr);
|
||||
this.parameters = parameters;
|
||||
this.serverSocket = serverSocket;
|
||||
}
|
||||
|
||||
/** @return the address to which this forwarder is bound for listening */
|
||||
public SocketAddress getListeningAddress() {
|
||||
return ss.getLocalSocketAddress();
|
||||
protected DirectTCPIPChannel openChannel(Socket socket)
|
||||
throws TransportException, ConnectionException {
|
||||
final DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
|
||||
chan.open();
|
||||
return chan;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,16 +126,13 @@ public class LocalPortForwarder {
|
||||
*/
|
||||
public void listen()
|
||||
throws IOException {
|
||||
log.info("Listening on {}", ss.getLocalSocketAddress());
|
||||
Socket sock;
|
||||
log.info("Listening on {}", serverSocket.getLocalSocketAddress());
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
sock = ss.accept();
|
||||
log.info("Got connection from {}", sock.getRemoteSocketAddress());
|
||||
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, sock);
|
||||
chan.open();
|
||||
chan.start();
|
||||
final Socket socket = serverSocket.accept();
|
||||
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
|
||||
openChannel(socket).start();
|
||||
}
|
||||
log.info("Interrupted!");
|
||||
log.debug("Interrupted!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ import net.schmizz.sshj.connection.ConnectionException;
|
||||
import net.schmizz.sshj.connection.channel.Channel;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -81,12 +80,6 @@ public interface Session
|
||||
void signal(Signal signal)
|
||||
throws TransportException;
|
||||
|
||||
@Deprecated
|
||||
String getOutputAsString() throws IOException;
|
||||
|
||||
@Deprecated
|
||||
String getErrorAsString() throws IOException;
|
||||
|
||||
}
|
||||
|
||||
/** Shell API. */
|
||||
@@ -132,6 +125,7 @@ public interface Session
|
||||
/** Subsystem API. */
|
||||
interface Subsystem
|
||||
extends Channel {
|
||||
|
||||
Integer getExitStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,6 @@ import net.schmizz.sshj.connection.ConnectionException;
|
||||
import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -59,13 +58,13 @@ public class SessionChannel
|
||||
|
||||
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
|
||||
|
||||
private Integer exitStatus;
|
||||
private volatile Integer exitStatus;
|
||||
|
||||
private Signal exitSignal;
|
||||
private Boolean wasCoreDumped;
|
||||
private String exitErrMsg;
|
||||
private volatile Signal exitSignal;
|
||||
private volatile Boolean wasCoreDumped;
|
||||
private volatile String exitErrMsg;
|
||||
|
||||
private Boolean canDoFlowControl;
|
||||
private volatile Boolean canDoFlowControl;
|
||||
|
||||
private boolean usedUp;
|
||||
|
||||
@@ -76,7 +75,7 @@ public class SessionChannel
|
||||
@Override
|
||||
public void allocateDefaultPTY()
|
||||
throws ConnectionException, TransportException {
|
||||
allocatePTY("dummy", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
||||
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +91,7 @@ public class SessionChannel
|
||||
.putUInt32(width)
|
||||
.putUInt32(height)
|
||||
.putBytes(PTYMode.encode(modes))
|
||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +103,7 @@ public class SessionChannel
|
||||
public void changeWindowDimensions(int cols, int rows, int width, int height)
|
||||
throws TransportException {
|
||||
sendChannelRequest(
|
||||
"pty-req",
|
||||
"window-change",
|
||||
false,
|
||||
new Buffer.PlainBuffer()
|
||||
.putUInt32(cols)
|
||||
@@ -120,7 +119,7 @@ public class SessionChannel
|
||||
checkReuse();
|
||||
log.info("Will request to exec `{}`", command);
|
||||
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
usedUp = true;
|
||||
return this;
|
||||
}
|
||||
@@ -176,14 +175,14 @@ public class SessionChannel
|
||||
.putString(authProto)
|
||||
.putString(authCookie)
|
||||
.putUInt32(screen)
|
||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvVar(String name, String value)
|
||||
throws ConnectionException, TransportException {
|
||||
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,7 +195,7 @@ public class SessionChannel
|
||||
public Shell startShell()
|
||||
throws ConnectionException, TransportException {
|
||||
checkReuse();
|
||||
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
sendChannelRequest("shell", true, null).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
usedUp = true;
|
||||
return this;
|
||||
}
|
||||
@@ -207,7 +206,7 @@ public class SessionChannel
|
||||
checkReuse();
|
||||
log.info("Will request `{}` subsystem", name);
|
||||
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
usedUp = true;
|
||||
return this;
|
||||
}
|
||||
@@ -255,18 +254,4 @@ public class SessionChannel
|
||||
throw new SSHRuntimeException("This session channel is all used up");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String getOutputAsString()
|
||||
throws IOException {
|
||||
return IOUtils.readFully(getInputStream()).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String getErrorAsString()
|
||||
throws IOException {
|
||||
return IOUtils.readFully(getErrorStream()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,8 +54,9 @@ public abstract class AbstractForwardedChannel
|
||||
* First 2 args are standard; the others can be parsed from a CHANNEL_OPEN packet.
|
||||
*/
|
||||
|
||||
protected AbstractForwardedChannel(Connection conn, String type, int recipient, int remoteWinSize,
|
||||
int remoteMaxPacketSize, String origIP, int origPort) {
|
||||
protected AbstractForwardedChannel(Connection conn, String type,
|
||||
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||
String origIP, int origPort) {
|
||||
super(conn, type);
|
||||
this.origIP = origIP;
|
||||
this.origPort = origPort;
|
||||
@@ -65,20 +66,20 @@ public abstract class AbstractForwardedChannel
|
||||
@Override
|
||||
public void confirm()
|
||||
throws TransportException {
|
||||
log.info("Confirming `{}` channel #{}", getType(), getID());
|
||||
log.debug("Confirming `{}` channel #{}", getType(), getID());
|
||||
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
||||
conn.attach(this);
|
||||
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
|
||||
.putUInt32(getID())
|
||||
.putUInt32(getLocalWinSize())
|
||||
.putUInt32(getLocalMaxPacketSize()));
|
||||
open.set();
|
||||
.putUInt32(getID())
|
||||
.putUInt32(getLocalWinSize())
|
||||
.putUInt32(getLocalMaxPacketSize()));
|
||||
openEvent.set();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(Reason reason, String message)
|
||||
throws TransportException {
|
||||
log.info("Rejecting `{}` channel: {}", getType(), message);
|
||||
log.debug("Rejecting `{}` channel: {}", getType(), message);
|
||||
conn.sendOpenFailure(getRecipient(), reason, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,18 +39,18 @@ public class RemotePortForwarder
|
||||
* address (or domain name) and port on which connections for forwarding
|
||||
* are to be accepted. Some strings used for 'address to bind' have
|
||||
* special-case semantics.
|
||||
* <p/>
|
||||
*
|
||||
* o "" means that connections are to be accepted on all protocol
|
||||
* families supported by the SSH implementation.
|
||||
* <p/>
|
||||
*
|
||||
* o "0.0.0.0" means to listen on all IPv4 addresses.
|
||||
* <p/>
|
||||
*
|
||||
* o "::" means to listen on all IPv6 addresses.
|
||||
* <p/>
|
||||
*
|
||||
* o "localhost" means to listen on all protocol families supported by
|
||||
* the SSH implementation on loopback addresses only ([RFC3330] and
|
||||
* [RFC3513]).
|
||||
* <p/>
|
||||
*
|
||||
* o "127.0.0.1" and "::1" indicate listening on the loopback
|
||||
* interfaces for IPv4 and IPv6, respectively.
|
||||
* </pre>
|
||||
@@ -127,7 +127,8 @@ public class RemotePortForwarder
|
||||
|
||||
private final Forward fwd;
|
||||
|
||||
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
|
||||
public ForwardedTCPIPChannel(Connection conn,
|
||||
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||
Forward fwd, String origIP, int origPort) {
|
||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||
this.fwd = fwd;
|
||||
@@ -198,9 +199,9 @@ public class RemotePortForwarder
|
||||
protected SSHPacket req(String reqName, Forward forward)
|
||||
throws ConnectionException, TransportException {
|
||||
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
|
||||
.getCompactData();
|
||||
.getCompactData();
|
||||
return conn.sendGlobalRequest(reqName, true, specifics)
|
||||
.retrieve(conn.getTimeout(), TimeUnit.SECONDS);
|
||||
.retrieve(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/** @return the active forwards. */
|
||||
@@ -217,7 +218,7 @@ public class RemotePortForwarder
|
||||
throws ConnectionException, TransportException {
|
||||
final ForwardedTCPIPChannel chan;
|
||||
try {
|
||||
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt(),
|
||||
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
|
||||
new Forward(buf.readString(), buf.readUInt32AsInt()),
|
||||
buf.readString(), buf.readUInt32AsInt());
|
||||
} catch (Buffer.BufferException be) {
|
||||
@@ -227,7 +228,7 @@ public class RemotePortForwarder
|
||||
callListener(listeners.get(chan.getParentForward()), chan);
|
||||
else
|
||||
chan.reject(OpenFailException.Reason.ADMINISTRATIVELY_PROHIBITED, "Forwarding was not requested on `"
|
||||
+ chan.getParentForward() + "`");
|
||||
+ chan.getParentForward() + "`");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,7 @@ public class SocketForwardingConnectListener
|
||||
@Override
|
||||
public void gotConnect(Channel.Forwarded chan)
|
||||
throws IOException {
|
||||
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
|
||||
log.debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
|
||||
|
||||
final Socket sock = new Socket();
|
||||
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
|
||||
@@ -66,4 +66,4 @@ public class SocketForwardingConnectListener
|
||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,8 +34,9 @@ public class X11Forwarder
|
||||
|
||||
public static final String TYPE = "x11";
|
||||
|
||||
public X11Channel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize, String origIP,
|
||||
int origPort) {
|
||||
public X11Channel(Connection conn,
|
||||
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||
String origIP, int origPort) {
|
||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||
}
|
||||
|
||||
@@ -58,8 +59,7 @@ public class X11Forwarder
|
||||
throws ConnectionException, TransportException {
|
||||
try {
|
||||
callListener(listener, new X11Channel(conn,
|
||||
buf.readUInt32AsInt(),
|
||||
buf.readUInt32AsInt(), buf.readUInt32AsInt(),
|
||||
buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
|
||||
buf.readString(), buf.readUInt32AsInt()));
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new ConnectionException(be);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -74,7 +74,7 @@ public class FileMode {
|
||||
}
|
||||
|
||||
public int getTypeMask() {
|
||||
return mask & 0770000;
|
||||
return mask & 0170000;
|
||||
}
|
||||
|
||||
public int getPermissionsMask() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -56,24 +56,25 @@ public class PacketReader
|
||||
throws IOException {
|
||||
readIntoBuffer(lenBuf, 0, lenBuf.length);
|
||||
|
||||
return (int) (lenBuf[0] << 24 & 0xff000000L
|
||||
| lenBuf[1] << 16 & 0x00ff0000L
|
||||
| lenBuf[2] << 8 & 0x0000ff00L
|
||||
| lenBuf[3] & 0x000000ffL);
|
||||
final long len = (lenBuf[0] << 24 & 0xff000000L
|
||||
| lenBuf[1] << 16 & 0x00ff0000L
|
||||
| lenBuf[2] << 8 & 0x0000ff00L
|
||||
| lenBuf[3] & 0x000000ffL);
|
||||
|
||||
if (len > SFTPPacket.MAX_SIZE) {
|
||||
throw new IllegalStateException("Invalid packet: indicated length "+len+" too large");
|
||||
}
|
||||
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
public SFTPPacket<Response> readPacket()
|
||||
throws IOException {
|
||||
int len = getPacketLength();
|
||||
|
||||
packet.rpos(0);
|
||||
packet.wpos(0);
|
||||
|
||||
final int len = getPacketLength();
|
||||
packet.clear();
|
||||
packet.ensureCapacity(len);
|
||||
readIntoBuffer(packet.array(), 0, len);
|
||||
|
||||
packet.wpos(len);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
@@ -97,13 +98,16 @@ public class PacketReader
|
||||
log.debug("Received {} packet", resp.getType());
|
||||
if (promise == null)
|
||||
throw new SFTPException("Received [" + resp.readType() + "] response for request-id " + resp.getRequestID()
|
||||
+ ", no such request was made");
|
||||
+ ", no such request was made");
|
||||
else
|
||||
promise.deliver(resp);
|
||||
}
|
||||
|
||||
public void expectResponseTo(Request req) {
|
||||
promises.put(req.getRequestID(), req.getResponsePromise());
|
||||
public Promise<Response, SFTPException> expectResponseTo(long requestId) {
|
||||
final Promise<Response, SFTPException> promise
|
||||
= new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer);
|
||||
promises.put(requestId, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,15 +19,27 @@ import java.io.IOException;
|
||||
|
||||
public class PathHelper {
|
||||
|
||||
public interface Canonicalizer {
|
||||
|
||||
String canonicalize(String path)
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
||||
public static final String DEFAULT_PATH_SEPARATOR = "/";
|
||||
|
||||
private final SFTPEngine engine;
|
||||
private final Canonicalizer canonicalizer;
|
||||
private final String pathSep;
|
||||
|
||||
private String dotDir;
|
||||
|
||||
public PathHelper(SFTPEngine engine, String pathSep) {
|
||||
this.engine = engine;
|
||||
private synchronized String getDotDir() // cached
|
||||
throws IOException {
|
||||
return (dotDir != null) ? dotDir : (dotDir = canonicalizer.canonicalize("."));
|
||||
}
|
||||
|
||||
public PathHelper(Canonicalizer canonicalizer, String pathSep) {
|
||||
this.canonicalizer = canonicalizer;
|
||||
this.pathSep = pathSep;
|
||||
}
|
||||
|
||||
@@ -47,37 +59,33 @@ public class PathHelper {
|
||||
return new PathComponents(parent, name, pathSep);
|
||||
}
|
||||
|
||||
public PathComponents getComponents(String path)
|
||||
/**
|
||||
* Divide the path into {@code PathComponents(parent, name)} while making sure {@code name != "." && name != ".."}
|
||||
*
|
||||
* @param path to convert
|
||||
*
|
||||
* @return PathComponents
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public PathComponents getComponents(final String path)
|
||||
throws IOException {
|
||||
if (path.isEmpty() || path.equals("."))
|
||||
if (path.equals(pathSep))
|
||||
return getComponents("", "");
|
||||
|
||||
if (path.isEmpty() || path.equals(".") || path.equals("." + pathSep))
|
||||
return getComponents(getDotDir());
|
||||
|
||||
final int lastSlash = path.lastIndexOf(pathSep);
|
||||
final String withoutTrailSep = trimTrailingSeparator(path);
|
||||
final int lastSep = withoutTrailSep.lastIndexOf(pathSep);
|
||||
final String parent = (lastSep == -1) ? "" : withoutTrailSep.substring(0, lastSep);
|
||||
final String name = (lastSep == -1) ? withoutTrailSep : withoutTrailSep.substring(lastSep + pathSep.length());
|
||||
|
||||
if (lastSlash == -1) // Relative path
|
||||
if (path.equals(".."))
|
||||
return getComponents(canon(path));
|
||||
else
|
||||
return getComponents(getDotDir(), path);
|
||||
|
||||
final String name = path.substring(lastSlash + pathSep.length());
|
||||
|
||||
if (name.equals(".") || name.equals(".."))
|
||||
return getComponents(canon(path));
|
||||
else {
|
||||
final String parent = path.substring(0, lastSlash);
|
||||
if (name.equals(".") || name.equals("..")) {
|
||||
return getComponents(canonicalizer.canonicalize(path));
|
||||
} else {
|
||||
return getComponents(parent, name);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized String getDotDir()
|
||||
throws IOException {
|
||||
return (dotDir != null) ? dotDir : (dotDir = canon("."));
|
||||
}
|
||||
|
||||
private String canon(String path)
|
||||
throws IOException {
|
||||
return engine.canonicalize(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RemoteDirectory
|
||||
extends RemoteResource {
|
||||
@@ -32,8 +33,9 @@ public class RemoteDirectory
|
||||
throws IOException {
|
||||
List<RemoteResourceInfo> rri = new LinkedList<RemoteResourceInfo>();
|
||||
loop:
|
||||
for (; ;) {
|
||||
Response res = requester.doRequest(newRequest(PacketType.READDIR));
|
||||
for (; ; ) {
|
||||
final Response res = requester.request(newRequest(PacketType.READDIR))
|
||||
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
switch (res.getType()) {
|
||||
|
||||
case NAME:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,11 +15,15 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.concurrent.Promise;
|
||||
import net.schmizz.sshj.sftp.Response.StatusCode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RemoteFile
|
||||
extends RemoteResource {
|
||||
@@ -28,17 +32,10 @@ public class RemoteFile
|
||||
super(requester, path, handle);
|
||||
}
|
||||
|
||||
public RemoteFileInputStream getInputStream() {
|
||||
return new RemoteFileInputStream();
|
||||
}
|
||||
|
||||
public RemoteFileOutputStream getOutputStream() {
|
||||
return new RemoteFileOutputStream();
|
||||
}
|
||||
|
||||
public FileAttributes fetchAttributes()
|
||||
throws IOException {
|
||||
return requester.doRequest(newRequest(PacketType.FSTAT))
|
||||
return requester.request(newRequest(PacketType.FSTAT))
|
||||
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
|
||||
.ensurePacketTypeIs(PacketType.ATTRS)
|
||||
.readFileAttributes();
|
||||
}
|
||||
@@ -55,7 +52,9 @@ public class RemoteFile
|
||||
|
||||
public int read(long fileOffset, byte[] to, int offset, int len)
|
||||
throws IOException {
|
||||
Response res = requester.doRequest(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
|
||||
final Response res = requester.request(
|
||||
newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len)
|
||||
).retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
switch (res.getType()) {
|
||||
case DATA:
|
||||
int recvLen = res.readUInt32AsInt();
|
||||
@@ -73,42 +72,61 @@ public class RemoteFile
|
||||
|
||||
public void write(long fileOffset, byte[] data, int off, int len)
|
||||
throws IOException {
|
||||
requester.doRequest(newRequest(PacketType.WRITE)
|
||||
.putUInt64(fileOffset)
|
||||
.putUInt32(len - off)
|
||||
.putRawBytes(data, off, len)
|
||||
).ensureStatusPacketIsOK();
|
||||
checkResponse(asyncWrite(fileOffset, data, off, len));
|
||||
}
|
||||
|
||||
protected Promise<Response, SFTPException> asyncWrite(long fileOffset, byte[] data, int off, int len)
|
||||
throws IOException {
|
||||
return requester.request(newRequest(PacketType.WRITE)
|
||||
.putUInt64(fileOffset)
|
||||
.putUInt32(len - off)
|
||||
.putRawBytes(data, off, len)
|
||||
);
|
||||
}
|
||||
|
||||
private void checkResponse(Promise<Response, SFTPException> responsePromise)
|
||||
throws SFTPException {
|
||||
responsePromise.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
|
||||
}
|
||||
|
||||
public void setAttributes(FileAttributes attrs)
|
||||
throws IOException {
|
||||
requester.doRequest(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs)).ensureStatusPacketIsOK();
|
||||
requester.request(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs))
|
||||
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
|
||||
}
|
||||
|
||||
public int getOutgoingPacketOverhead() {
|
||||
return 1 + // packet type
|
||||
4 + // request id
|
||||
4 + // next length
|
||||
handle.length() + // next
|
||||
8 + // file offset
|
||||
4 + // data length
|
||||
4; // packet length
|
||||
4 + // request id
|
||||
4 + // next length
|
||||
handle.length() + // next
|
||||
8 + // file offset
|
||||
4 + // data length
|
||||
4; // packet length
|
||||
}
|
||||
|
||||
public class RemoteFileOutputStream
|
||||
extends OutputStream {
|
||||
|
||||
|
||||
private final byte[] b = new byte[1];
|
||||
|
||||
private final int maxUnconfirmedWrites;
|
||||
private final Queue<Promise<Response, SFTPException>> unconfirmedWrites;
|
||||
|
||||
private long fileOffset;
|
||||
|
||||
public RemoteFileOutputStream() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public RemoteFileOutputStream(long fileOffset) {
|
||||
this.fileOffset = fileOffset;
|
||||
public RemoteFileOutputStream(long startingOffset) {
|
||||
this(startingOffset, 0);
|
||||
}
|
||||
|
||||
public RemoteFileOutputStream(long startingOffset, int maxUnconfirmedWrites) {
|
||||
this.fileOffset = startingOffset;
|
||||
this.maxUnconfirmedWrites = maxUnconfirmedWrites;
|
||||
this.unconfirmedWrites = new LinkedList<Promise<Response, SFTPException>>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,10 +139,27 @@ public class RemoteFile
|
||||
@Override
|
||||
public void write(byte[] buf, int off, int len)
|
||||
throws IOException {
|
||||
RemoteFile.this.write(fileOffset, buf, off, len);
|
||||
if (unconfirmedWrites.size() > maxUnconfirmedWrites) {
|
||||
checkResponse(unconfirmedWrites.remove());
|
||||
}
|
||||
unconfirmedWrites.add(RemoteFile.this.asyncWrite(fileOffset, buf, off, len));
|
||||
fileOffset += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
throws IOException {
|
||||
while (!unconfirmedWrites.isEmpty()) {
|
||||
checkResponse(unconfirmedWrites.remove());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException {
|
||||
flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class RemoteFileInputStream
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class RemoteResource
|
||||
implements Closeable {
|
||||
@@ -48,8 +49,10 @@ public abstract class RemoteResource
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException {
|
||||
log.info("Closing `{}`", this);
|
||||
requester.doRequest(newRequest(PacketType.CLOSE)).ensureStatusPacketIsOK();
|
||||
log.debug("Closing `{}`", this);
|
||||
requester.request(newRequest(PacketType.CLOSE))
|
||||
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
|
||||
.ensureStatusPacketIsOK();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,20 +15,16 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.concurrent.Promise;
|
||||
|
||||
public class Request
|
||||
public final class Request
|
||||
extends SFTPPacket<Request> {
|
||||
|
||||
private final PacketType type;
|
||||
private final long reqID;
|
||||
private final Promise<Response, SFTPException> responsePromise;
|
||||
|
||||
public Request(PacketType type, long reqID) {
|
||||
super(type);
|
||||
this.type = type;
|
||||
this.reqID = reqID;
|
||||
responsePromise = new Promise<Response, SFTPException>("sftp / " + reqID, SFTPException.chainer);
|
||||
putUInt32(reqID);
|
||||
}
|
||||
|
||||
@@ -40,10 +36,6 @@ public class Request
|
||||
return type;
|
||||
}
|
||||
|
||||
public Promise<Response, SFTPException> getResponsePromise() {
|
||||
return responsePromise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Request{" + reqID + ";" + type + "}";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.concurrent.Promise;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Requester {
|
||||
@@ -23,7 +25,9 @@ public interface Requester {
|
||||
|
||||
Request newRequest(PacketType type);
|
||||
|
||||
Response doRequest(Request req)
|
||||
Promise<Response, SFTPException> request(Request req)
|
||||
throws IOException;
|
||||
|
||||
int getTimeoutMs();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@ package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
|
||||
public class Response
|
||||
public final class Response
|
||||
extends SFTPPacket<Response> {
|
||||
|
||||
public static enum StatusCode {
|
||||
@@ -51,7 +51,8 @@ public class Response
|
||||
private final PacketType type;
|
||||
private final long reqID;
|
||||
|
||||
public Response(Buffer<Response> pk, int protocolVersion) throws SFTPException {
|
||||
public Response(Buffer<Response> pk, int protocolVersion)
|
||||
throws SFTPException {
|
||||
super(pk);
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.type = readType();
|
||||
@@ -74,7 +75,8 @@ public class Response
|
||||
return type;
|
||||
}
|
||||
|
||||
public StatusCode readStatusCode() throws SFTPException {
|
||||
public StatusCode readStatusCode()
|
||||
throws SFTPException {
|
||||
try {
|
||||
return StatusCode.fromInt(readUInt32AsInt());
|
||||
} catch (BufferException be) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ public class SFTPClient
|
||||
return engine;
|
||||
}
|
||||
|
||||
public SFTPFileTransfer getFileTansfer() {
|
||||
public SFTPFileTransfer getFileTransfer() {
|
||||
return xfer;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.concurrent.Promise;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
import net.schmizz.sshj.connection.channel.direct.Session.Subsystem;
|
||||
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
|
||||
@@ -34,12 +35,12 @@ public class SFTPEngine
|
||||
implements Requester, Closeable {
|
||||
|
||||
public static final int MAX_SUPPORTED_VERSION = 3;
|
||||
public static final int DEFAULT_TIMEOUT = 30;
|
||||
public static final int DEFAULT_TIMEOUT_MS = 30 * 1000; // way too long, but it was the original default
|
||||
|
||||
/** Logger */
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected volatile int timeout = DEFAULT_TIMEOUT;
|
||||
protected volatile int timeoutMs = DEFAULT_TIMEOUT_MS;
|
||||
|
||||
protected final PathHelper pathHelper;
|
||||
|
||||
@@ -56,11 +57,18 @@ public class SFTPEngine
|
||||
this(ssh, PathHelper.DEFAULT_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
public SFTPEngine(SessionFactory ssh, String pathSep) throws SSHException {
|
||||
public SFTPEngine(SessionFactory ssh, String pathSep)
|
||||
throws SSHException {
|
||||
sub = ssh.startSession().startSubsystem("sftp");
|
||||
out = sub.getOutputStream();
|
||||
reader = new PacketReader(this);
|
||||
pathHelper = new PathHelper(this, pathSep);
|
||||
pathHelper = new PathHelper(new PathHelper.Canonicalizer() {
|
||||
@Override
|
||||
public String canonicalize(String path)
|
||||
throws IOException {
|
||||
return SFTPEngine.this.canonicalize(path);
|
||||
}
|
||||
}, pathSep);
|
||||
}
|
||||
|
||||
public SFTPEngine init()
|
||||
@@ -74,7 +82,7 @@ public class SFTPEngine
|
||||
throw new SFTPException("Expected INIT packet, received: " + type);
|
||||
|
||||
operativeVersion = response.readUInt32AsInt();
|
||||
log.info("Server version {}", operativeVersion);
|
||||
log.debug("Server version {}", operativeVersion);
|
||||
if (MAX_SUPPORTED_VERSION < operativeVersion)
|
||||
throw new SFTPException("Server reported incompatible protocol version: " + operativeVersion);
|
||||
|
||||
@@ -109,12 +117,17 @@ public class SFTPEngine
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response doRequest(Request req)
|
||||
public Promise<Response, SFTPException> request(Request req)
|
||||
throws IOException {
|
||||
reader.expectResponseTo(req);
|
||||
final Promise<Response, SFTPException> promise = reader.expectResponseTo(req.getRequestID());
|
||||
log.debug("Sending {}", req);
|
||||
transmit(req);
|
||||
return req.getResponsePromise().retrieve(timeout, TimeUnit.SECONDS);
|
||||
return promise;
|
||||
}
|
||||
|
||||
private Response doRequest(Request req)
|
||||
throws IOException {
|
||||
return request(req).retrieve(getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
|
||||
@@ -220,12 +233,12 @@ public class SFTPEngine
|
||||
));
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
public void setTimeoutMs(int timeoutMs) {
|
||||
this.timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
public int getTimeoutMs() {
|
||||
return timeoutMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,15 +38,24 @@ public class SFTPFileTransfer
|
||||
|
||||
private volatile LocalFileFilter uploadFilter;
|
||||
private volatile RemoteResourceFilter downloadFilter;
|
||||
private volatile boolean preserveAttributes = true;
|
||||
|
||||
public SFTPFileTransfer(SFTPEngine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
public boolean getPreserveAttributes() {
|
||||
return preserveAttributes;
|
||||
}
|
||||
|
||||
public void setPreserveAttributes(boolean preserveAttributes) {
|
||||
this.preserveAttributes = preserveAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(String source, String dest)
|
||||
throws IOException {
|
||||
new Uploader().upload(new FileSystemFile(source), dest);
|
||||
upload(new FileSystemFile(source), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,7 +67,7 @@ public class SFTPFileTransfer
|
||||
@Override
|
||||
public void upload(LocalSourceFile localFile, String remotePath)
|
||||
throws IOException {
|
||||
new Uploader().upload(localFile, remotePath);
|
||||
new Uploader().upload(getTransferListener(), localFile, remotePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +75,7 @@ public class SFTPFileTransfer
|
||||
throws IOException {
|
||||
final PathComponents pathComponents = engine.getPathHelper().getComponents(source);
|
||||
final FileAttributes attributes = engine.stat(source);
|
||||
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), dest);
|
||||
new Downloader().download(getTransferListener(), new RemoteResourceInfo(pathComponents, attributes), dest);
|
||||
}
|
||||
|
||||
public void setUploadFilter(LocalFileFilter uploadFilter) {
|
||||
@@ -87,58 +96,61 @@ public class SFTPFileTransfer
|
||||
|
||||
private class Downloader {
|
||||
|
||||
private final TransferListener listener = getTransferListener();
|
||||
|
||||
private void download(final RemoteResourceInfo remote, final LocalDestFile local)
|
||||
private void download(final TransferListener listener,
|
||||
final RemoteResourceInfo remote,
|
||||
final LocalDestFile local)
|
||||
throws IOException {
|
||||
final LocalDestFile adjustedFile;
|
||||
switch (remote.getAttributes().getType()) {
|
||||
case DIRECTORY:
|
||||
listener.startedDir(remote.getName());
|
||||
adjustedFile = downloadDir(remote, local);
|
||||
listener.finishedDir();
|
||||
adjustedFile = downloadDir(listener.directory(remote.getName()), remote, local);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
log.warn("Server did not supply information about the type of file at `{}` " +
|
||||
"-- assuming it is a regular file!", remote.getPath());
|
||||
case REGULAR:
|
||||
listener.startedFile(remote.getName(), remote.getAttributes().getSize());
|
||||
adjustedFile = downloadFile(remote, local);
|
||||
listener.finishedFile();
|
||||
adjustedFile = downloadFile(listener.file(remote.getName(), remote.getAttributes().getSize()),
|
||||
remote, local);
|
||||
break;
|
||||
default:
|
||||
throw new IOException(remote + " is not a regular file or directory");
|
||||
}
|
||||
copyAttributes(remote, adjustedFile);
|
||||
|
||||
if (getPreserveAttributes())
|
||||
copyAttributes(remote, adjustedFile);
|
||||
}
|
||||
|
||||
private LocalDestFile downloadDir(final RemoteResourceInfo remote, final LocalDestFile local)
|
||||
private LocalDestFile downloadDir(final TransferListener listener,
|
||||
final RemoteResourceInfo remote,
|
||||
final LocalDestFile local)
|
||||
throws IOException {
|
||||
final LocalDestFile adjusted = local.getTargetDirectory(remote.getName());
|
||||
final RemoteDirectory rd = engine.openDir(remote.getPath());
|
||||
try {
|
||||
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
||||
download(rri, adjusted.getChild(rri.getName()));
|
||||
download(listener, rri, adjusted.getChild(rri.getName()));
|
||||
} finally {
|
||||
rd.close();
|
||||
}
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private LocalDestFile downloadFile(final RemoteResourceInfo remote, final LocalDestFile local)
|
||||
private LocalDestFile downloadFile(final StreamCopier.Listener listener,
|
||||
final RemoteResourceInfo remote,
|
||||
final LocalDestFile local)
|
||||
throws IOException {
|
||||
final LocalDestFile adjusted = local.getTargetFile(remote.getName());
|
||||
final RemoteFile rf = engine.open(remote.getPath());
|
||||
try {
|
||||
final RemoteFile.RemoteFileInputStream rfis = rf.new RemoteFileInputStream();
|
||||
final OutputStream os = adjusted.getOutputStream();
|
||||
try {
|
||||
new StreamCopier(rf.getInputStream(), os)
|
||||
new StreamCopier(rfis, os)
|
||||
.bufSize(engine.getSubsystem().getLocalMaxPacketSize())
|
||||
.keepFlushing(false)
|
||||
.listener(listener)
|
||||
.copy();
|
||||
} finally {
|
||||
rfis.close();
|
||||
os.close();
|
||||
}
|
||||
} finally {
|
||||
@@ -161,33 +173,34 @@ public class SFTPFileTransfer
|
||||
|
||||
private class Uploader {
|
||||
|
||||
private final TransferListener listener = getTransferListener();
|
||||
|
||||
private void upload(LocalSourceFile local, String remote)
|
||||
private void upload(final TransferListener listener,
|
||||
final LocalSourceFile local,
|
||||
final String remote)
|
||||
throws IOException {
|
||||
final String adjustedPath;
|
||||
if (local.isDirectory()) {
|
||||
listener.startedDir(local.getName());
|
||||
adjustedPath = uploadDir(local, remote);
|
||||
listener.finishedDir();
|
||||
adjustedPath = uploadDir(listener.directory(local.getName()), local, remote);
|
||||
} else if (local.isFile()) {
|
||||
listener.startedFile(local.getName(), local.getLength());
|
||||
adjustedPath = uploadFile(local, remote);
|
||||
listener.finishedFile();
|
||||
adjustedPath = uploadFile(listener.file(local.getName(), local.getLength()), local, remote);
|
||||
} else
|
||||
throw new IOException(local + " is not a file or directory");
|
||||
engine.setAttributes(adjustedPath, getAttributes(local));
|
||||
if (getPreserveAttributes())
|
||||
engine.setAttributes(adjustedPath, getAttributes(local));
|
||||
}
|
||||
|
||||
private String uploadDir(LocalSourceFile local, String remote)
|
||||
private String uploadDir(final TransferListener listener,
|
||||
final LocalSourceFile local,
|
||||
final String remote)
|
||||
throws IOException {
|
||||
final String adjusted = prepareDir(local, remote);
|
||||
for (LocalSourceFile f : local.getChildren(getUploadFilter()))
|
||||
upload(f, adjusted);
|
||||
upload(listener, f, adjusted);
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private String uploadFile(LocalSourceFile local, String remote)
|
||||
private String uploadFile(final StreamCopier.Listener listener,
|
||||
final LocalSourceFile local,
|
||||
final String remote)
|
||||
throws IOException {
|
||||
final String adjusted = prepareFile(local, remote);
|
||||
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
|
||||
@@ -195,14 +208,16 @@ public class SFTPFileTransfer
|
||||
OpenMode.TRUNC));
|
||||
try {
|
||||
final InputStream fis = local.getInputStream();
|
||||
final RemoteFile.RemoteFileOutputStream rfos = rf.new RemoteFileOutputStream(0, 16);
|
||||
try {
|
||||
new StreamCopier(fis, rf.getOutputStream())
|
||||
new StreamCopier(fis, rfos)
|
||||
.bufSize(engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead())
|
||||
.keepFlushing(false)
|
||||
.listener(listener)
|
||||
.copy();
|
||||
} finally {
|
||||
fis.close();
|
||||
rfos.close();
|
||||
}
|
||||
} finally {
|
||||
rf.close();
|
||||
@@ -210,7 +225,7 @@ public class SFTPFileTransfer
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private String prepareDir(LocalSourceFile local, String remote)
|
||||
private String prepareDir(final LocalSourceFile local, final String remote)
|
||||
throws IOException {
|
||||
final FileAttributes attrs;
|
||||
try {
|
||||
@@ -236,7 +251,7 @@ public class SFTPFileTransfer
|
||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
||||
}
|
||||
|
||||
private String prepareFile(LocalSourceFile local, String remote)
|
||||
private String prepareFile(final LocalSourceFile local, final String remote)
|
||||
throws IOException {
|
||||
final FileAttributes attrs;
|
||||
try {
|
||||
@@ -250,8 +265,7 @@ public class SFTPFileTransfer
|
||||
}
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
||||
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
||||
remote = engine.getPathHelper().adjustForParent(remote, local.getName());
|
||||
return remote;
|
||||
return engine.getPathHelper().adjustForParent(remote, local.getName());
|
||||
} else {
|
||||
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
||||
return remote;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.sshj.xfer.LocalDestFile;
|
||||
import net.schmizz.sshj.xfer.LocalSourceFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -28,7 +31,7 @@ public class StatefulSFTPClient
|
||||
throws IOException {
|
||||
super(engine);
|
||||
this.cwd = getSFTPEngine().canonicalize(".");
|
||||
log.info("Start dir = " + cwd);
|
||||
log.debug("Start dir = {}", cwd);
|
||||
}
|
||||
|
||||
private synchronized String cwdify(String path) {
|
||||
@@ -37,11 +40,12 @@ public class StatefulSFTPClient
|
||||
|
||||
public synchronized void cd(String dirname)
|
||||
throws IOException {
|
||||
cwd = cwdify(dirname);
|
||||
final String targetCwd = cwdify(dirname);
|
||||
if (statExistence(cwd) == null) {
|
||||
throw new SFTPException(cwd + ": does not exist");
|
||||
}
|
||||
log.info("CWD = " + cwd);
|
||||
cwd = targetCwd;
|
||||
log.debug("CWD = {}", cwd);
|
||||
}
|
||||
|
||||
public synchronized List<RemoteResourceInfo> ls()
|
||||
@@ -178,10 +182,22 @@ public class StatefulSFTPClient
|
||||
super.get(cwdify(source), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void get(String source, LocalDestFile dest)
|
||||
throws IOException {
|
||||
super.get(cwdify(source), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String source, String dest)
|
||||
throws IOException {
|
||||
super.put(source, cwdify(dest));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(LocalSourceFile source, String dest)
|
||||
throws IOException {
|
||||
super.put(source, cwdify(dest));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -90,9 +90,9 @@ public abstract class AbstractSignature
|
||||
| sig[i++] & 0x000000ff;
|
||||
i += j;
|
||||
j = sig[i++] << 24 & 0xff000000
|
||||
| sig[i++] << 16 & 0x00ff0000
|
||||
| sig[i++] << 8 & 0x0000ff00
|
||||
| sig[i++] & 0x000000ff;
|
||||
| sig[i++] << 16 & 0x00ff0000
|
||||
| sig[i++] << 8 & 0x0000ff00
|
||||
| sig[i++] & 0x000000ff;
|
||||
byte[] newSig = new byte[j];
|
||||
System.arraycopy(sig, i, newSig, 0, j);
|
||||
sig = newSig;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ import net.schmizz.sshj.transport.mac.MAC;
|
||||
* <p/>
|
||||
* <pre>
|
||||
* Each packet is in the following format:
|
||||
* <p/>
|
||||
*
|
||||
* uint32 packet_length
|
||||
* byte padding_length
|
||||
* byte[n1] payload; n1 = packet_length - padding_length - 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -88,7 +88,7 @@ final class Decoder
|
||||
int need;
|
||||
|
||||
/* Decoding loop */
|
||||
for (; ;)
|
||||
for (; ; )
|
||||
|
||||
if (packetLength == -1) // Waiting for beginning of packet
|
||||
{
|
||||
@@ -124,7 +124,7 @@ final class Decoder
|
||||
if (log.isTraceEnabled())
|
||||
log.trace("Received packet #{}: {}", seq, plain.printHex());
|
||||
|
||||
packetHandler.handle(plain.readMessageID(), plain); // Process the decoded packet //
|
||||
packetHandler.handle(plain.readMessageID(), plain); // Process the decoded packet
|
||||
|
||||
inputBuffer.clear();
|
||||
packetLength = -1;
|
||||
@@ -166,7 +166,7 @@ final class Decoder
|
||||
}
|
||||
|
||||
if (isInvalidPacketLength(len)) { // Check packet length validity
|
||||
log.info("Error decoding packet (invalid length) {}", inputBuffer.printHex());
|
||||
log.error("Error decoding packet (invalid length) {}", inputBuffer.printHex());
|
||||
throw new TransportException(DisconnectReason.PROTOCOL_ERROR, "invalid packet length: " + len);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,7 @@ final class Encoder
|
||||
private SSHPacket checkHeaderSpace(SSHPacket buffer) {
|
||||
if (buffer.rpos() < 5) {
|
||||
log.warn("Performance cost: when sending a packet, ensure that "
|
||||
+ "5 bytes are available in front of the buffer");
|
||||
+ "5 bytes are available in front of the buffer");
|
||||
SSHPacket nb = new SSHPacket(buffer.available() + 5);
|
||||
nb.rpos(5);
|
||||
nb.wpos(5);
|
||||
@@ -96,8 +96,6 @@ final class Encoder
|
||||
long encode(SSHPacket buffer) {
|
||||
encodeLock.lock();
|
||||
try {
|
||||
buffer = checkHeaderSpace(buffer);
|
||||
|
||||
if (log.isTraceEnabled())
|
||||
log.trace("Encoding packet #{}: {}", seq, buffer.printHex());
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -80,7 +80,7 @@ final class Heartbeater
|
||||
while (!isInterrupted()) {
|
||||
final int hi = getPositiveInterval();
|
||||
if (trans.isRunning()) {
|
||||
log.info("Sending heartbeat since {} seconds elapsed", hi);
|
||||
log.debug("Sending heartbeat since {} seconds elapsed", hi);
|
||||
trans.write(new SSHPacket(Message.IGNORE));
|
||||
}
|
||||
Thread.sleep(hi * 1000);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,13 +35,12 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport;
|
||||
|
||||
import net.schmizz.concurrent.Event;
|
||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||
import net.schmizz.concurrent.Event;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.DisconnectReason;
|
||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.Message;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
@@ -57,6 +56,7 @@ import net.schmizz.sshj.transport.verification.HostKeyVerifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Arrays;
|
||||
@@ -155,7 +155,7 @@ final class KeyExchanger
|
||||
* @param waitForDone whether should block till key exchange completed
|
||||
*
|
||||
* @throws TransportException if there is an error during key exchange
|
||||
* @see {@link Transport#setTimeout} for setting timeout for kex
|
||||
* @see {@link Transport#setTimeoutMs} for setting timeout for kex
|
||||
*/
|
||||
void startKex(boolean waitForDone)
|
||||
throws TransportException {
|
||||
@@ -169,7 +169,7 @@ final class KeyExchanger
|
||||
|
||||
void waitForDone()
|
||||
throws TransportException {
|
||||
done.await(transport.getTimeout(), TimeUnit.SECONDS);
|
||||
done.await(transport.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private synchronized void ensureKexOngoing()
|
||||
@@ -192,7 +192,7 @@ final class KeyExchanger
|
||||
*/
|
||||
private void sendKexInit()
|
||||
throws TransportException {
|
||||
log.info("Sending SSH_MSG_KEXINIT");
|
||||
log.debug("Sending SSH_MSG_KEXINIT");
|
||||
clientProposal = new Proposal(transport.getConfig());
|
||||
transport.write(clientProposal.getPacket());
|
||||
kexInitSent.set();
|
||||
@@ -200,7 +200,7 @@ final class KeyExchanger
|
||||
|
||||
private void sendNewKeys()
|
||||
throws TransportException {
|
||||
log.info("Sending SSH_MSG_NEWKEYS");
|
||||
log.debug("Sending SSH_MSG_NEWKEYS");
|
||||
transport.write(new SSHPacket(Message.NEWKEYS));
|
||||
}
|
||||
|
||||
@@ -234,17 +234,16 @@ final class KeyExchanger
|
||||
|
||||
private void gotKexInit(SSHPacket buf)
|
||||
throws TransportException {
|
||||
Proposal serverProposal = new Proposal(buf);
|
||||
buf.rpos(buf.rpos() - 1);
|
||||
final Proposal serverProposal = new Proposal(buf);
|
||||
negotiatedAlgs = clientProposal.negotiate(serverProposal);
|
||||
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
|
||||
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(), negotiatedAlgs
|
||||
.getKeyExchangeAlgorithm());
|
||||
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(),
|
||||
negotiatedAlgs.getKeyExchangeAlgorithm());
|
||||
try {
|
||||
kex.init(transport,
|
||||
transport.getServerID().getBytes(IOUtils.UTF8),
|
||||
transport.getClientID().getBytes(IOUtils.UTF8),
|
||||
buf.getCompactData(),
|
||||
clientProposal.getPacket().getCompactData());
|
||||
transport.getServerID(), transport.getClientID(),
|
||||
serverProposal.getPacket().getCompactData(), clientProposal.getPacket().getCompactData());
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e);
|
||||
}
|
||||
@@ -262,7 +261,7 @@ final class KeyExchanger
|
||||
*
|
||||
* @return the resized key
|
||||
*/
|
||||
private static byte[] resizedKey(byte[] E, int blockSize, Digest hash, byte[] K, byte[] H) {
|
||||
private static byte[] resizedKey(byte[] E, int blockSize, Digest hash, BigInteger K, byte[] H) {
|
||||
while (blockSize > E.length) {
|
||||
Buffer.PlainBuffer buffer = new Buffer.PlainBuffer().putMPInt(K).putRawBytes(H).putRawBytes(E);
|
||||
hash.update(buffer.array(), 0, buffer.available());
|
||||
@@ -280,13 +279,15 @@ final class KeyExchanger
|
||||
private void gotNewKeys() {
|
||||
final Digest hash = kex.getHash();
|
||||
|
||||
final byte[] H = kex.getH();
|
||||
|
||||
if (sessionID == null)
|
||||
// session id is 'H' from the first key exchange and does not change thereafter
|
||||
sessionID = Arrays.copyOf(kex.getH(), kex.getH().length);
|
||||
sessionID = H;
|
||||
|
||||
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer()
|
||||
.putMPInt(kex.getK())
|
||||
.putRawBytes(kex.getH())
|
||||
.putRawBytes(H)
|
||||
.putByte((byte) 0) // <placeholder>
|
||||
.putRawBytes(sessionID);
|
||||
final int pos = hashInput.available() - sessionID.length - 1; // Position of <placeholder>
|
||||
@@ -353,21 +354,20 @@ final class KeyExchanger
|
||||
|
||||
case KEXINIT:
|
||||
ensureReceivedMatchesExpected(msg, Message.KEXINIT);
|
||||
log.info("Received SSH_MSG_KEXINIT");
|
||||
log.debug("Received SSH_MSG_KEXINIT");
|
||||
startKex(false); // Will start key exchange if not already on
|
||||
/*
|
||||
* We block on this event to prevent a race condition where we may have received a SSH_MSG_KEXINIT before
|
||||
* having sent the packet ourselves (would cause gotKexInit() to fail)
|
||||
*/
|
||||
kexInitSent.await(transport.getTimeout(), TimeUnit.SECONDS);
|
||||
buf.rpos(buf.rpos() - 1);
|
||||
kexInitSent.await(transport.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||
gotKexInit(buf);
|
||||
expected = Expected.FOLLOWUP;
|
||||
break;
|
||||
|
||||
case FOLLOWUP:
|
||||
ensureKexOngoing();
|
||||
log.info("Received kex followup data");
|
||||
log.debug("Received kex followup data");
|
||||
try {
|
||||
if (kex.next(msg, buf)) {
|
||||
verifyHost(kex.getHostKey());
|
||||
@@ -382,7 +382,7 @@ final class KeyExchanger
|
||||
case NEWKEYS:
|
||||
ensureReceivedMatchesExpected(msg, Message.NEWKEYS);
|
||||
ensureKexOngoing();
|
||||
log.info("Received SSH_MSG_NEWKEYS");
|
||||
log.debug("Received SSH_MSG_NEWKEYS");
|
||||
gotNewKeys();
|
||||
setKexDone();
|
||||
expected = Expected.KEXINIT;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,15 +92,15 @@ public final class NegotiatedAlgorithms {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("[ " + //
|
||||
"kex=" + kex + "; " + //
|
||||
"sig=" + sig + "; " + //
|
||||
"c2sCipher=" + c2sCipher + "; " + //
|
||||
"s2cCipher=" + s2cCipher + "; " + //
|
||||
"c2sMAC=" + c2sMAC + "; " + //
|
||||
"s2cMAC=" + s2cMAC + "; " + //
|
||||
"c2sComp=" + c2sComp + "; " + //
|
||||
"s2cComp=" + s2cComp + //
|
||||
return ("[ " +
|
||||
"kex=" + kex + "; " +
|
||||
"sig=" + sig + "; " +
|
||||
"c2sCipher=" + c2sCipher + "; " +
|
||||
"s2cCipher=" + s2cCipher + "; " +
|
||||
"c2sMAC=" + c2sMAC + "; " +
|
||||
"s2cMAC=" + s2cMAC + "; " +
|
||||
"c2sComp=" + c2sComp + "; " +
|
||||
"s2cComp=" + s2cComp +
|
||||
" ]");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,7 +86,8 @@ class Proposal {
|
||||
packet.putUInt32(0); // "Reserved" for future by spec
|
||||
}
|
||||
|
||||
public Proposal(SSHPacket packet) throws TransportException {
|
||||
public Proposal(SSHPacket packet)
|
||||
throws TransportException {
|
||||
this.packet = packet;
|
||||
final int savedPos = packet.rpos();
|
||||
packet.rpos(packet.rpos() + 17); // Skip message ID & cookie
|
||||
@@ -144,14 +145,14 @@ class Proposal {
|
||||
public NegotiatedAlgorithms negotiate(Proposal other)
|
||||
throws TransportException {
|
||||
return new NegotiatedAlgorithms(
|
||||
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), //
|
||||
firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), //
|
||||
firstMatch(this.getClient2ServerCipherAlgorithms(), other.getClient2ServerCipherAlgorithms()), //
|
||||
firstMatch(this.getServer2ClientCipherAlgorithms(), other.getServer2ClientCipherAlgorithms()), //
|
||||
firstMatch(this.getClient2ServerMACAlgorithms(), other.getClient2ServerMACAlgorithms()), //
|
||||
firstMatch(this.getServer2ClientMACAlgorithms(), other.getServer2ClientMACAlgorithms()), //
|
||||
firstMatch(this.getClient2ServerCompressionAlgorithms(), other.getClient2ServerCompressionAlgorithms()), //
|
||||
firstMatch(this.getServer2ClientCompressionAlgorithms(), other.getServer2ClientCompressionAlgorithms()) //
|
||||
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()),
|
||||
firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()),
|
||||
firstMatch(this.getClient2ServerCipherAlgorithms(), other.getClient2ServerCipherAlgorithms()),
|
||||
firstMatch(this.getServer2ClientCipherAlgorithms(), other.getServer2ClientCipherAlgorithms()),
|
||||
firstMatch(this.getClient2ServerMACAlgorithms(), other.getClient2ServerMACAlgorithms()),
|
||||
firstMatch(this.getServer2ClientMACAlgorithms(), other.getServer2ClientMACAlgorithms()),
|
||||
firstMatch(this.getClient2ServerCompressionAlgorithms(), other.getClient2ServerCompressionAlgorithms()),
|
||||
firstMatch(this.getServer2ClientCompressionAlgorithms(), other.getServer2ClientCompressionAlgorithms())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 sshj contributors
|
||||
* Copyright 2010-2012 sshj contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,14 +86,14 @@ public interface Transport
|
||||
Config getConfig();
|
||||
|
||||
/** @return the timeout that is currently set for blocking operations. */
|
||||
int getTimeout();
|
||||
int getTimeoutMs();
|
||||
|
||||
/**
|
||||
* Set a timeout for methods that may block.
|
||||
*
|
||||
* @param timeout the timeout in seconds
|
||||
* @param timeout the timeout in milliseconds
|
||||
*/
|
||||
void setTimeout(int timeout);
|
||||
void setTimeoutMs(int timeout);
|
||||
|
||||
/** @return the interval in seconds at which a heartbeat message is sent to the server */
|
||||
int getHeartbeatInterval();
|
||||
@@ -178,12 +178,14 @@ public interface Transport
|
||||
*/
|
||||
void join()
|
||||
throws TransportException;
|
||||
|
||||
/**
|
||||
* Joins the thread calling this method to the transport's death.
|
||||
*
|
||||
* @throws TransportException if the transport dies of an exception
|
||||
*/
|
||||
void join(int timeout, TimeUnit unit) throws TransportException;
|
||||
void join(int timeout, TimeUnit unit)
|
||||
throws TransportException;
|
||||
|
||||
/** Send a disconnection packet with reason as {@link DisconnectReason#BY_APPLICATION}, and closes this transport. */
|
||||
void disconnect();
|
||||
@@ -226,9 +228,7 @@ public interface Transport
|
||||
*/
|
||||
void setDisconnectListener(DisconnectListener listener);
|
||||
|
||||
/**
|
||||
* @return the current disconnect listener.
|
||||
*/
|
||||
/** @return the current disconnect listener. */
|
||||
DisconnectListener getDisconnectListener();
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user