mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-08 08:10:55 +03:00
Compare commits
187 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a95fad89a0 | ||
|
|
83c5f2f815 | ||
|
|
b17d3fe867 | ||
|
|
3cefda5bd3 | ||
|
|
18f364a283 | ||
|
|
d68032a9b8 | ||
|
|
c73ba8bfa7 | ||
|
|
7bbfd40627 | ||
|
|
7ae84be548 | ||
|
|
f2793d1acf | ||
|
|
bca5883422 | ||
|
|
3e54e2c955 | ||
|
|
a7802ddcde | ||
|
|
a7872b394b | ||
|
|
3ade3977ef | ||
|
|
efb2c547f9 | ||
|
|
703a0df09d | ||
|
|
73de5b7b08 | ||
|
|
665cbf078a | ||
|
|
b3ea908996 | ||
|
|
11da49a4e7 | ||
|
|
5b1f9f2a7d | ||
|
|
268de458e3 | ||
|
|
834f0f22cd | ||
|
|
1daf456cbe | ||
|
|
ea11d34ac8 | ||
|
|
e961dc1b27 | ||
|
|
25fbff245f | ||
|
|
333c23e167 | ||
|
|
cf32842d0d | ||
|
|
70720de71b | ||
|
|
44e1ce1358 | ||
|
|
921f41f9de | ||
|
|
34c4be848a | ||
|
|
d10e303b1a | ||
|
|
46791c87f5 | ||
|
|
af0d873e5b | ||
|
|
d37b54b1fd | ||
|
|
c4408ac6dd | ||
|
|
ebbf440304 | ||
|
|
ef5a54d33f | ||
|
|
66514836c8 | ||
|
|
e943d80049 | ||
|
|
81931f3b7a | ||
|
|
b8bfc19ecf | ||
|
|
0cb62c6d44 | ||
|
|
0ccc57b5af | ||
|
|
4806b1d6c7 | ||
|
|
ecc1d06dc2 | ||
|
|
d95586508d | ||
|
|
5ee2f0a417 | ||
|
|
2a7278d239 | ||
|
|
0875417dde | ||
|
|
0a3ad4f68f | ||
|
|
fe58ecdee5 | ||
|
|
264e10b40c | ||
|
|
a00015969b | ||
|
|
d6c22fef55 | ||
|
|
9886facf42 | ||
|
|
01be48508d | ||
|
|
bdc541c959 | ||
|
|
f2ebbe288f | ||
|
|
9297338195 | ||
|
|
a8d2ea2028 | ||
|
|
f34667521d | ||
|
|
77f5d7fdb8 | ||
|
|
08d0e59b6b | ||
|
|
5c540b6889 | ||
|
|
baa8c8e995 | ||
|
|
f354fd6661 | ||
|
|
93f1543af8 | ||
|
|
63424657da | ||
|
|
131e85c4d0 | ||
|
|
587684c6a8 | ||
|
|
66f67db21b | ||
|
|
3356f533d0 | ||
|
|
97535bbcae | ||
|
|
896b0ea288 | ||
|
|
60d54fa5de | ||
|
|
06e421e752 | ||
|
|
b5796f5e74 | ||
|
|
0f7355a277 | ||
|
|
466ff99e1c | ||
|
|
1f992c3fae | ||
|
|
df6019accc | ||
|
|
fdb891b842 | ||
|
|
5159a799df | ||
|
|
78e5a2e30e | ||
|
|
db22f08f97 | ||
|
|
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 |
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# IntelliJ IDEA
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# Eclipe
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Output dirs
|
||||||
|
target/
|
||||||
|
build/
|
||||||
|
.gradle/
|
||||||
|
|
||||||
|
|
||||||
1
.travis.yml
Normal file
1
.travis.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
language: java
|
||||||
@@ -1,8 +1 @@
|
|||||||
Shikhar Bhushan <shikhar@schmizz.net>
|
git log --format='%aN <%aE>' | awk '{arr[$0]++} END{for (i in arr){print arr[i], i;}}' | sort -rn | cut -d\ -f2-
|
||||||
Cyril Ledru <cledru@keynectis.net>
|
|
||||||
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>
|
|
||||||
|
|||||||
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
|||||||
sshj - SSHv2 library for Java
|
sshj - SSHv2 library for Java
|
||||||
Copyright 2010-2011 sshj contributors
|
Copyright 2010-2012 sshj contributors
|
||||||
|
|
||||||
This product includes code derived from software developed at
|
This product includes code derived from software developed at
|
||||||
The Apache Software Foundation (http://www.apache.org/):
|
The Apache Software Foundation (http://www.apache.org/):
|
||||||
|
|||||||
54
README.adoc
Normal file
54
README.adoc
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
= sshj - SSHv2 library for Java
|
||||||
|
|
||||||
|
image::https://travis-ci.org/hierynomus/sshj.svg?branch=master[]
|
||||||
|
|
||||||
|
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
|
||||||
|
|
||||||
|
== Features of the library include:
|
||||||
|
|
||||||
|
* reading known_hosts files for host key verification
|
||||||
|
* publickey, password and keyboard-interactive authentication
|
||||||
|
* command, subsystem and shell channels
|
||||||
|
* local and remote port forwarding
|
||||||
|
* scp + complete sftp version 0-3 implementation
|
||||||
|
|
||||||
|
== Supported algorithms
|
||||||
|
|
||||||
|
Implementations / adapters for the following algorithms are included:
|
||||||
|
|
||||||
|
ciphers::
|
||||||
|
`aes{128,192,256}-{cbc,ctr}`, `blowfish-cbc`, `3des-cbc`
|
||||||
|
|
||||||
|
key exchange::
|
||||||
|
`diffie-hellman-group1-sha1`, `diffie-hellman-group14-sha1`
|
||||||
|
|
||||||
|
signatures::
|
||||||
|
`ssh-rsa`, `ssh-dss`
|
||||||
|
|
||||||
|
mac::
|
||||||
|
`hmac-md5`, `hmac-md5-96`, `hmac-sha1`, `hmac-sha1-96`, `hmac-sha2-256`, `hmac-sha2-512`
|
||||||
|
|
||||||
|
compression::
|
||||||
|
`zlib` and `zlib@openssh.com` (delayed zlib)
|
||||||
|
|
||||||
|
private key files::
|
||||||
|
`pkcs8` encoded (what openssh uses)
|
||||||
|
|
||||||
|
If you need something that is not included, it shouldn't be too hard to add (do contribute it!)
|
||||||
|
|
||||||
|
|
||||||
|
== Dependencies
|
||||||
|
|
||||||
|
Java 6+. http://www.slf4j.org/download.html[slf4j] is required. http://www.bouncycastle.org/java.html[bouncycastle] is highly recommended and required for using some of the crypto algorithms. http://www.jcraft.com/jzlib/[jzlib] is required for using zlib compression.
|
||||||
|
|
||||||
|
== Reporting bugs
|
||||||
|
|
||||||
|
Issue tracker https://github.com/hierynomus/sshj/issues
|
||||||
|
|
||||||
|
== Discussion
|
||||||
|
|
||||||
|
Google Group http://groups.google.com/group/sshj-users
|
||||||
|
|
||||||
|
== Contributing
|
||||||
|
|
||||||
|
Fork away!
|
||||||
58
README.rst
58
README.rst
@@ -1,58 +0,0 @@
|
|||||||
sshj - SSHv2 library for Java
|
|
||||||
==============================
|
|
||||||
|
|
||||||
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
|
|
||||||
|
|
||||||
Features of the library include:
|
|
||||||
|
|
||||||
* reading known_hosts files for host key verification
|
|
||||||
* publickey, password and keyboard-interactive authentication
|
|
||||||
* command, subsystem and shell channels
|
|
||||||
* local and remote port forwarding
|
|
||||||
* scp + complete sftp version 0-3 implementation
|
|
||||||
|
|
||||||
Implementations / adapters for the following algorithms are included:
|
|
||||||
|
|
||||||
ciphers
|
|
||||||
``aes{128,192,256}-{cbc,ctr}``, ``blowfish-cbc``, ``3des-cbc``
|
|
||||||
|
|
||||||
key exchange
|
|
||||||
``diffie-hellman-group1-sha1``, ``diffie-hellman-group14-sha1``
|
|
||||||
|
|
||||||
signatures
|
|
||||||
``ssh-rsa``, ``ssh-dss``
|
|
||||||
|
|
||||||
mac
|
|
||||||
``hmac-md5``, ``hmac-md5-96``, ``hmac-sha1``, ``hmac-sha1-96``
|
|
||||||
|
|
||||||
compression
|
|
||||||
``zlib`` and ``zlib@openssh.com`` (delayed zlib)
|
|
||||||
|
|
||||||
private key files
|
|
||||||
``pkcs8`` encoded (what openssh uses)
|
|
||||||
|
|
||||||
If you need something that is not included, it shouldn't be too hard to add (do contribute it!)
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Bugs, questions
|
|
||||||
----------------
|
|
||||||
|
|
||||||
`Issue tracker <https://github.com/shikhar/sshj/issues>`_
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Fork away!
|
|
||||||
|
|
||||||
|
|
||||||
.. _slf4j: http://www.slf4j.org/download.html
|
|
||||||
|
|
||||||
.. _bouncycastle: http://www.bouncycastle.org/java.html
|
|
||||||
|
|
||||||
.. _jzlib: http://www.jcraft.com/jzlib/
|
|
||||||
177
build-publishing.gradle
Normal file
177
build-publishing.gradle
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "signing"
|
||||||
|
|
||||||
|
group = "nl.javadude"
|
||||||
|
version = "0.10.1-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compile {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
pom
|
||||||
|
}
|
||||||
|
|
||||||
|
def bouncycastleVersion = "1.50"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.slf4j:slf4j-api:1.7.7"
|
||||||
|
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "com.jcraft:jzlib:1.1.3"
|
||||||
|
|
||||||
|
testCompile "junit:junit:4.11"
|
||||||
|
testCompile "org.mockito:mockito-core:1.9.5"
|
||||||
|
testCompile "org.apache.sshd:sshd-core:0.11.0"
|
||||||
|
testRuntime "ch.qos.logback:logback-classic:1.1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
task generatePom(type: GenerateMavenPom) {
|
||||||
|
destination = file("$buildDir/generated-pom.xml")
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar, sourcesJar
|
||||||
|
pom generatePom.destination
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
sign configurations.archives
|
||||||
|
}
|
||||||
|
|
||||||
|
task signPom(type: Sign) {
|
||||||
|
sign configurations.pom
|
||||||
|
}
|
||||||
|
|
||||||
|
def getSignatureFiles = {
|
||||||
|
def allFiles = project.tasks.signArchives.signatureFiles.collect { it }
|
||||||
|
def signedSources = allFiles.find { it.name.contains('-sources') }
|
||||||
|
def signedJavadoc = allFiles.find { it.name.contains('-javadoc') }
|
||||||
|
def signedJar = (allFiles - [signedSources, signedJavadoc])[0]
|
||||||
|
return [
|
||||||
|
[archive: signedSources, classifier: 'sources', extension: 'jar.asc'],
|
||||||
|
[archive: signedJavadoc, classifier: 'javadoc', extension: 'jar.asc'],
|
||||||
|
[archive: signedJar, classifier: null, extension: 'jar.asc']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def getPomSignature = {
|
||||||
|
return project.tasks.signPom.signatureFiles.collect{it}[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
gpgJars(MavenPublication) {
|
||||||
|
getSignatureFiles().each {signature ->
|
||||||
|
artifact (signature.archive) {
|
||||||
|
classifier = signature.classifier
|
||||||
|
extension = signature.extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gpgPom(MavenPublication) {
|
||||||
|
artifact(getPomSignature()) {
|
||||||
|
classifier = null
|
||||||
|
extension = "pom.asc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maven(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
artifact (javadocJar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
}
|
||||||
|
|
||||||
|
artifact (sourcesJar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.withXml {
|
||||||
|
asNode().children().last() + {
|
||||||
|
resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
|
name "sshj"
|
||||||
|
description "SSHv2 library for Java"
|
||||||
|
url "https://github.com/hierynomus/sshj"
|
||||||
|
inceptionYear "2009"
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system "github"
|
||||||
|
url "https://github.com/hierynomus/sshj/issues"
|
||||||
|
}
|
||||||
|
|
||||||
|
scm {
|
||||||
|
connection "scm:git:git://github.com/hierynomus/sshj.git"
|
||||||
|
developerConnection "scm:git:git@github.com:hierynomus/sshj.git"
|
||||||
|
url "https://github.com/hierynomus/sshj.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name "Apache 2"
|
||||||
|
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
distribution "repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id "hierynomus"
|
||||||
|
name "Jeroen van Erp"
|
||||||
|
email "jeroen@javadude.nl"
|
||||||
|
roles {
|
||||||
|
role "Lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "shikhar"
|
||||||
|
name "Shikhar Bhushan"
|
||||||
|
email "shikhar@schmizz.net"
|
||||||
|
url "http://schmizz.net"
|
||||||
|
roles {
|
||||||
|
role "Previous lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "iterate"
|
||||||
|
name "David Kocher"
|
||||||
|
email "dkocher@iterate.ch"
|
||||||
|
organization "iterage GmbH"
|
||||||
|
organizationUrl "https://iterate.ch"
|
||||||
|
roles {
|
||||||
|
role "Developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file:/${project.projectDir}/artifacts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.afterEvaluate { p ->
|
||||||
|
p.tasks.publishGpgPomPublicationToMavenRepository.dependsOn("generatePom", "signPom")
|
||||||
|
}
|
||||||
|
|
||||||
|
generatePom.configure {
|
||||||
|
pom = publishing.publications.getByName("maven").pom
|
||||||
|
}
|
||||||
156
build.gradle
Normal file
156
build.gradle
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "maven"
|
||||||
|
apply plugin: "signing"
|
||||||
|
apply plugin: "osgi"
|
||||||
|
|
||||||
|
group = "nl.javadude"
|
||||||
|
version = "0.11.0-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compile {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
include "**/*Test.*"
|
||||||
|
afterSuite { descriptor, result ->
|
||||||
|
def indicator = "\u001B[32m✓\u001b[0m"
|
||||||
|
if (result.failedTestCount > 0) {
|
||||||
|
indicator = "\u001B[31m✘\u001b[0m"
|
||||||
|
}
|
||||||
|
logger.lifecycle("$indicator Test ${descriptor.name}; Executed: ${result.testCount}/\u001B[32m${result.successfulTestCount}\u001B[0m/\u001B[31m${result.failedTestCount}\u001B[0m")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def bouncycastleVersion = "1.51"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.slf4j:slf4j-api:1.7.7"
|
||||||
|
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "com.jcraft:jzlib:1.1.3"
|
||||||
|
|
||||||
|
testCompile "junit:junit:4.11"
|
||||||
|
testCompile "org.mockito:mockito-core:1.9.5"
|
||||||
|
testCompile "org.apache.sshd:sshd-core:0.11.0"
|
||||||
|
testRuntime "ch.qos.logback:logback-classic:1.1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
instruction "Bundle-Description", "SSHv2 library for Java"
|
||||||
|
instruction "Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
instruction "Import-Package", "!net.schmizz.*"
|
||||||
|
instruction "Import-Package", "javax.crypto*"
|
||||||
|
instruction "Import-Package", "com.jcraft.jzlib*;version=\"[1.1,2)\";resolution:=optional"
|
||||||
|
instruction "Import-Package", "org.slf4j*;version=\"[1.7,5)\""
|
||||||
|
instruction "Import-Package", "org.bouncycastle*"
|
||||||
|
instruction "Import-Package", "*"
|
||||||
|
instruction "Export-Package", "net.schmizz.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar, sourcesJar
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
required { !version.contains("SNAPSHOT") && gradle.taskGraph.hasTask("uploadArchives") }
|
||||||
|
sign configurations.archives
|
||||||
|
}
|
||||||
|
|
||||||
|
// This disables the pedantic doclint feature of JDK8
|
||||||
|
if (JavaVersion.current().isJava8Compatible()) {
|
||||||
|
tasks.withType(Javadoc) {
|
||||||
|
options.addStringOption('Xdoclint:none', '-quiet')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadArchives {
|
||||||
|
if(project.hasProperty('sonatypeUsername')) {
|
||||||
|
repositories.mavenDeployer {
|
||||||
|
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||||
|
|
||||||
|
configuration = configurations.archives
|
||||||
|
|
||||||
|
repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
|
||||||
|
authentication(userName: sonatypeUsername, password: sonatypePassword)
|
||||||
|
}
|
||||||
|
snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') {
|
||||||
|
authentication(userName: sonatypeUsername, password: sonatypePassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.project {
|
||||||
|
name "sshj"
|
||||||
|
description "SSHv2 library for Java"
|
||||||
|
url "https://github.com/hierynomus/sshj"
|
||||||
|
inceptionYear "2009"
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system "github"
|
||||||
|
url "https://github.com/hierynomus/sshj/issues"
|
||||||
|
}
|
||||||
|
|
||||||
|
scm {
|
||||||
|
connection "scm:git:git://github.com/hierynomus/sshj.git"
|
||||||
|
developerConnection "scm:git:git@github.com:hierynomus/sshj.git"
|
||||||
|
url "https://github.com/hierynomus/sshj.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name "Apache 2"
|
||||||
|
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
distribution "repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id "hierynomus"
|
||||||
|
name "Jeroen van Erp"
|
||||||
|
email "jeroen@javadude.nl"
|
||||||
|
roles {
|
||||||
|
role "Lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "shikhar"
|
||||||
|
name "Shikhar Bhushan"
|
||||||
|
email "shikhar@schmizz.net"
|
||||||
|
url "http://schmizz.net"
|
||||||
|
roles {
|
||||||
|
role "Previous lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "iterate"
|
||||||
|
name "David Kocher"
|
||||||
|
email "dkocher@iterate.ch"
|
||||||
|
organization "iterage GmbH"
|
||||||
|
organizationUrl "https://iterate.ch"
|
||||||
|
roles {
|
||||||
|
role "Developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
examples/pom.xml
Normal file
101
examples/pom.xml
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright 2009 sshj contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>net.schmizz</groupId>
|
||||||
|
<artifactId>sshj</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>0.10.0</version>
|
||||||
|
|
||||||
|
<name>sshj-examples</name>
|
||||||
|
<description>Examples for SSHv2 library for Java</description>
|
||||||
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
|
|
||||||
|
<inceptionYear>2015</inceptionYear>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>github</system>
|
||||||
|
<url>http://github.com/hierynomus/sshj/issues</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:git://github.com/hierynomus/sshj.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:hierynomus/sshj.git</developerConnection>
|
||||||
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache 2</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.schmizz</groupId>
|
||||||
|
<artifactId>sshj</artifactId>
|
||||||
|
<version>0.10.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>hierynomus</id>
|
||||||
|
<name>Jeroen van Erp</name>
|
||||||
|
<email>jeroen@hierynomus.com</email>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>shikhar</id>
|
||||||
|
<name>Shikhar Bhushan</name>
|
||||||
|
<email>shikhar@schmizz.net</email>
|
||||||
|
<url>http://schmizz.net</url>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>iterate</id>
|
||||||
|
<name>David Kocher</name>
|
||||||
|
<email>dkocher@iterate.ch</email>
|
||||||
|
<organization>iterate GmbH</organization>
|
||||||
|
<organizationUrl>https://iterate.ch</organizationUrl>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,12 +13,14 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
|
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
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
|
* 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
|
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
|
||||||
* google.com:80
|
* google.com:80
|
||||||
*/
|
*/
|
||||||
ssh.newLocalPortForwarder(new InetSocketAddress("localhost", 8080), "google.com", 80)
|
final LocalPortForwarder.Parameters params
|
||||||
.listen();
|
= 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 {
|
} finally {
|
||||||
ssh.disconnect();
|
ssh.disconnect();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward;
|
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.xfer.FileSystemFile;
|
import net.schmizz.sshj.xfer.FileSystemFile;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.xfer.FileSystemFile;
|
import net.schmizz.sshj.xfer.FileSystemFile;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.sftp.SFTPClient;
|
import net.schmizz.sshj.sftp.SFTPClient;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.sftp.SFTPClient;
|
import net.schmizz.sshj.sftp.SFTPClient;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package examples;
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
254
pom.xml
254
pom.xml
@@ -1,28 +1,46 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<!--
|
||||||
|
|
||||||
|
Copyright 2009 sshj contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>net.schmizz</groupId>
|
<groupId>net.schmizz</groupId>
|
||||||
<artifactId>sshj</artifactId>
|
<artifactId>sshj</artifactId>
|
||||||
<packaging>bundle</packaging>
|
<packaging>bundle</packaging>
|
||||||
<version>0.6.0</version>
|
<version>0.10.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<name>sshj</name>
|
<name>sshj</name>
|
||||||
<description>SSHv2 library for Java</description>
|
<description>SSHv2 library for Java</description>
|
||||||
<url>http://github.com/shikhar/sshj</url>
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
|
|
||||||
<inceptionYear>2009</inceptionYear>
|
<inceptionYear>2009</inceptionYear>
|
||||||
|
|
||||||
<issueManagement>
|
<issueManagement>
|
||||||
<system>github</system>
|
<system>github</system>
|
||||||
<url>http://github.com/shikhar/sshj/issues</url>
|
<url>http://github.com/hierynomus/sshj/issues</url>
|
||||||
</issueManagement>
|
</issueManagement>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:git://github.com/shikhar/sshj.git</connection>
|
<connection>scm:git:git://github.com/hierynomus/sshj.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:shikhar/sshj.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:hierynomus/sshj.git</developerConnection>
|
||||||
<url>http://github.com/shikhar/sshj</url>
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
@@ -33,64 +51,112 @@
|
|||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.sonatype.oss</groupId>
|
||||||
|
<artifactId>oss-parent</artifactId>
|
||||||
|
<version>7</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.51</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
<version>1.51</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jzlib</artifactId>
|
||||||
|
<version>1.1.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>1.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>1.6.1</version>
|
<version>1.7.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>bcprov-jdk16</artifactId>
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
<version>1.46</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
<version>4.8.2</version>
|
<scope>provided</scope>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.jcraft</groupId>
|
<groupId>com.jcraft</groupId>
|
||||||
<artifactId>jzlib</artifactId>
|
<artifactId>jzlib</artifactId>
|
||||||
<version>1.0.7</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.sshd</groupId>
|
<groupId>org.apache.sshd</groupId>
|
||||||
<artifactId>sshd-core</artifactId>
|
<artifactId>sshd-core</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.11.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-core</artifactId>
|
<artifactId>logback-core</artifactId>
|
||||||
<version>0.9.29</version>
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.11</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>0.9.29</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-all</artifactId>
|
<artifactId>mockito-all</artifactId>
|
||||||
<version>1.9.0-rc1</version>
|
<version>1.9.5</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>hierynomus</id>
|
||||||
|
<name>Jeroen van Erp</name>
|
||||||
|
<email>jeroen@hierynomus.com</email>
|
||||||
|
</developer>
|
||||||
<developer>
|
<developer>
|
||||||
<id>shikhar</id>
|
<id>shikhar</id>
|
||||||
<name>Shikhar Bhushan</name>
|
<name>Shikhar Bhushan</name>
|
||||||
<email>shikhar@schmizz.net</email>
|
<email>shikhar@schmizz.net</email>
|
||||||
<url>http://schmizz.net</url>
|
<url>http://schmizz.net</url>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>iterate</id>
|
||||||
|
<name>David Kocher</name>
|
||||||
|
<email>dkocher@iterate.ch</email>
|
||||||
|
<organization>iterate GmbH</organization>
|
||||||
|
<organizationUrl>https://iterate.ch</organizationUrl>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -102,45 +168,16 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>2.3.2</version>
|
<version>3.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<excludes>
|
|
||||||
<exclude>examples/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<source>1.6</source>
|
<source>1.6</source>
|
||||||
<target>1.6</target>
|
<target>1.6</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<mavenExecutorId>forked-path</mavenExecutorId>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
|
||||||
<version>2.2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<descriptors>
|
|
||||||
<descriptor>src/assemble/examples.xml</descriptor>
|
|
||||||
</descriptors>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>make-assembly</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>single</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>2.1.2</version>
|
<version>2.2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>attach-sources</id>
|
<id>attach-sources</id>
|
||||||
@@ -153,7 +190,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>2.8</version>
|
<version>2.9.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<encoding>${project.build.sourceEncoding}</encoding>
|
<encoding>${project.build.sourceEncoding}</encoding>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -169,23 +206,77 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
<artifactId>maven-bundle-plugin</artifactId>
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
<version>2.3.5</version>
|
<version>2.4.0</version>
|
||||||
<extensions>true</extensions>
|
<extensions>true</extensions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<instructions>
|
<instructions>
|
||||||
<Import-Package>
|
<Import-Package>
|
||||||
!net.schmizz.*,
|
!net.schmizz.*,
|
||||||
javax.crypto*,
|
javax.crypto*,
|
||||||
com.jcraft.jzlib*;version="[1.0,2)",
|
com.jcraft.jzlib*;version="[1.1,2)";resolution:=optional,
|
||||||
org.slf4j*;version="[1.6,2)",
|
org.slf4j*;version="[1.7,5)",
|
||||||
org.bouncycastle*;version="[1.4,2)",
|
org.bouncycastle*,
|
||||||
*
|
*
|
||||||
</Import-Package>
|
</Import-Package>
|
||||||
<Export-Package>net.schmizz.*</Export-Package>
|
<Export-Package>net.schmizz.*</Export-Package>
|
||||||
</instructions>
|
</instructions>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>clirr-maven-plugin</artifactId>
|
||||||
|
<version>2.6.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.mycila</groupId>
|
||||||
|
<artifactId>license-maven-plugin</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
<configuration>
|
||||||
|
<header>src/etc/license-header</header>
|
||||||
|
<properties>
|
||||||
|
<owner>sshj contributors</owner>
|
||||||
|
<email>sshj-users@googlegroups.com</email>
|
||||||
|
</properties>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/README</exclude>
|
||||||
|
<exclude>src/test/resources/**</exclude>
|
||||||
|
<exclude>src/main/resources/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- <plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>1.5</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.sonatype.plugins</groupId>
|
||||||
|
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||||
|
<version>1.6.2</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<serverId>ossrh</serverId>
|
||||||
|
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||||
|
<autoReleaseAfterClose>true</autoReleaseAfterClose>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
--> </plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
@@ -207,58 +298,47 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>bcprov-jdk16</artifactId>
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
<version>1.45</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.jcraft</groupId>
|
<groupId>com.jcraft</groupId>
|
||||||
<artifactId>jzlib</artifactId>
|
<artifactId>jzlib</artifactId>
|
||||||
<version>1.0.7</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-core</artifactId>
|
<artifactId>logback-core</artifactId>
|
||||||
<version>0.9.24</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>0.9.24</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</profile>
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
<id>release-sign-artifacts</id>
|
<id>doclint-java8-disable</id>
|
||||||
<activation>
|
<activation>
|
||||||
<property>
|
<jdk>[1.8,)</jdk>
|
||||||
<name>performRelease</name>
|
|
||||||
<value>true</value>
|
|
||||||
</property>
|
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>1.3</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<passphrase>${gpg.passphrase}</passphrase>
|
<additionalparam>-Xdoclint:none</additionalparam>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>sign-artifacts</id>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>sign</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>clirr-maven-plugin</artifactId>
|
||||||
|
<version>2.6.1</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
|
||||||
<id>examples</id>
|
|
||||||
<formats>
|
|
||||||
<format>zip</format>
|
|
||||||
</formats>
|
|
||||||
<fileSets>
|
|
||||||
<fileSet>
|
|
||||||
<directory>src/main/java/examples</directory>
|
|
||||||
<includes/>
|
|
||||||
<outputDirectory>examples</outputDirectory>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
|
||||||
</assembly>
|
|
||||||
13
src/etc/license-header
Normal file
13
src/etc/license-header
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright ${project.inceptionYear} ${owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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)
|
if (val != null)
|
||||||
return val;
|
return val;
|
||||||
log.debug("Awaiting <<{}>>", name);
|
log.debug("Awaiting <<{}>>", name);
|
||||||
while (val == null && pendingEx == null)
|
if (timeout == 0) {
|
||||||
if (timeout == 0)
|
while (val == null && pendingEx == null) {
|
||||||
cond.await();
|
cond.await();
|
||||||
else if (!cond.await(timeout, unit))
|
}
|
||||||
|
} else {
|
||||||
|
if (!cond.await(timeout, unit))
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
if (pendingEx != null) {
|
if (pendingEx != null) {
|
||||||
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
|
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
|
||||||
throw pendingEx;
|
throw pendingEx;
|
||||||
@@ -199,6 +202,16 @@ public class Promise<V, T extends Throwable> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether this promise was fulfilled with either a value or an error. */
|
||||||
|
public boolean isFulfilled() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return pendingEx != null || val != null;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @return whether this promise has threads waiting on it. */
|
/** @return whether this promise has threads waiting on it. */
|
||||||
public boolean hasWaiters() {
|
public boolean hasWaiters() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
34
src/main/java/net/schmizz/keepalive/Heartbeater.java
Normal file
34
src/main/java/net/schmizz/keepalive/Heartbeater.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.Message;
|
||||||
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
|
final class Heartbeater
|
||||||
|
extends KeepAlive {
|
||||||
|
|
||||||
|
Heartbeater(ConnectionImpl conn) {
|
||||||
|
super(conn, "heartbeater");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doKeepAlive() throws TransportException {
|
||||||
|
conn.getTransport().write(new SSHPacket(Message.IGNORE));
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/main/java/net/schmizz/keepalive/KeepAlive.java
Normal file
81
src/main/java/net/schmizz/keepalive/KeepAlive.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public abstract class KeepAlive extends Thread {
|
||||||
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
protected final ConnectionImpl conn;
|
||||||
|
|
||||||
|
protected int keepAliveInterval = 0;
|
||||||
|
|
||||||
|
protected KeepAlive(ConnectionImpl conn, String name) {
|
||||||
|
this.conn = conn;
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getKeepAliveInterval() {
|
||||||
|
return keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setKeepAliveInterval(int keepAliveInterval) {
|
||||||
|
this.keepAliveInterval = keepAliveInterval;
|
||||||
|
if (keepAliveInterval > 0 && getState() == State.NEW) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized protected int getPositiveInterval()
|
||||||
|
throws InterruptedException {
|
||||||
|
while (keepAliveInterval <= 0) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
return keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.debug("Starting {}, sending keep-alive every {} seconds", getClass().getSimpleName(), keepAliveInterval);
|
||||||
|
try {
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
final int hi = getPositiveInterval();
|
||||||
|
if (conn.getTransport().isRunning()) {
|
||||||
|
log.debug("Sending keep-alive since {} seconds elapsed", hi);
|
||||||
|
doKeepAlive();
|
||||||
|
}
|
||||||
|
Thread.sleep(hi * 1000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If we weren't interrupted, kill the transport, then this exception was unexpected.
|
||||||
|
// Else we're in shutdown-mode already, so don't forcibly kill the transport.
|
||||||
|
if (!isInterrupted()) {
|
||||||
|
conn.getTransport().die(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Stopping {}", getClass().getSimpleName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doKeepAlive() throws TransportException, ConnectionException;
|
||||||
|
}
|
||||||
39
src/main/java/net/schmizz/keepalive/KeepAliveProvider.java
Normal file
39
src/main/java/net/schmizz/keepalive/KeepAliveProvider.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
|
||||||
|
public abstract class KeepAliveProvider {
|
||||||
|
|
||||||
|
public static final KeepAliveProvider HEARTBEAT = new KeepAliveProvider() {
|
||||||
|
@Override
|
||||||
|
public KeepAlive provide(ConnectionImpl connection) {
|
||||||
|
return new Heartbeater(connection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final KeepAliveProvider KEEP_ALIVE = new KeepAliveProvider() {
|
||||||
|
@Override
|
||||||
|
public KeepAlive provide(ConnectionImpl connection) {
|
||||||
|
return new KeepAliveRunner(connection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public abstract KeepAlive provide(ConnectionImpl connection);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
73
src/main/java/net/schmizz/keepalive/KeepAliveRunner.java
Normal file
73
src/main/java/net/schmizz/keepalive/KeepAliveRunner.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static net.schmizz.sshj.common.DisconnectReason.CONNECTION_LOST;
|
||||||
|
|
||||||
|
public class KeepAliveRunner extends KeepAlive {
|
||||||
|
|
||||||
|
/** The max number of keep-alives that should be unanswered before killing the connection. */
|
||||||
|
private int maxAliveCount = 5;
|
||||||
|
|
||||||
|
/** The queue of promises. */
|
||||||
|
private final Queue<Promise<SSHPacket, ConnectionException>> queue =
|
||||||
|
new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
||||||
|
|
||||||
|
KeepAliveRunner(ConnectionImpl conn) {
|
||||||
|
super(conn, "keep-alive");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public int getMaxAliveCount() {
|
||||||
|
return maxAliveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void setMaxAliveCount(int maxAliveCount) {
|
||||||
|
this.maxAliveCount = maxAliveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doKeepAlive() throws TransportException, ConnectionException {
|
||||||
|
emptyQueue(queue);
|
||||||
|
checkMaxReached(queue);
|
||||||
|
queue.add(conn.sendGlobalRequest("keepalive@openssh.com", true, new byte[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMaxReached(Queue<Promise<SSHPacket, ConnectionException>> queue) throws ConnectionException {
|
||||||
|
if (queue.size() >= maxAliveCount) {
|
||||||
|
throw new ConnectionException(CONNECTION_LOST,
|
||||||
|
format("Did not receive any keep-alive response for %s seconds", maxAliveCount * keepAliveInterval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emptyQueue(Queue<Promise<SSHPacket, ConnectionException>> queue) {
|
||||||
|
Promise<SSHPacket, ConnectionException> peek = queue.peek();
|
||||||
|
while (peek != null && peek.isFulfilled()) {
|
||||||
|
log.debug("Received response from server to our keep-alive.");
|
||||||
|
queue.remove();
|
||||||
|
peek = queue.peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
protected final String name;
|
||||||
/** Transport layer */
|
/** Transport layer */
|
||||||
protected final Transport trans;
|
protected final Transport trans;
|
||||||
/** Timeout for blocking operations */
|
|
||||||
protected int timeout;
|
|
||||||
|
|
||||||
public AbstractService(String name, Transport trans) {
|
public AbstractService(String name, Transport trans) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
timeout = trans.getTimeout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -77,12 +74,6 @@ public abstract class AbstractService
|
|||||||
trans.reqService(this);
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.signature.Signature;
|
import net.schmizz.sshj.signature.Signature;
|
||||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
@@ -54,16 +55,16 @@ public interface Config {
|
|||||||
List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories();
|
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();
|
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();
|
List<Factory.Named<MAC>> getMACFactories();
|
||||||
|
|
||||||
@@ -144,4 +145,14 @@ public interface Config {
|
|||||||
*/
|
*/
|
||||||
void setVersion(String version);
|
void setVersion(String version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The provider that creates the keep-alive implementation of choice.
|
||||||
|
*/
|
||||||
|
KeepAliveProvider getKeepAliveProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the provider that provides the keep-alive implementation.
|
||||||
|
* @param keepAliveProvider keep-alive provider
|
||||||
|
*/
|
||||||
|
void setKeepAliveProvider(KeepAliveProvider keepAliveProvider);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,29 +12,10 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.signature.Signature;
|
import net.schmizz.sshj.signature.Signature;
|
||||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
@@ -54,6 +35,7 @@ public class ConfigImpl
|
|||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
private Factory<Random> randomFactory;
|
private Factory<Random> randomFactory;
|
||||||
|
private KeepAliveProvider keepAliveProvider;
|
||||||
|
|
||||||
private List<Factory.Named<KeyExchange>> kexFactories;
|
private List<Factory.Named<KeyExchange>> kexFactories;
|
||||||
private List<Factory.Named<Cipher>> cipherFactories;
|
private List<Factory.Named<Cipher>> cipherFactories;
|
||||||
@@ -166,4 +148,13 @@ public class ConfigImpl
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeepAliveProvider getKeepAliveProvider() {
|
||||||
|
return keepAliveProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setKeepAliveProvider(KeepAliveProvider keepAliveProvider) {
|
||||||
|
this.keepAliveProvider = keepAliveProvider;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,33 +12,14 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.common.SecurityUtils;
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
import net.schmizz.sshj.signature.SignatureDSA;
|
import net.schmizz.sshj.signature.SignatureDSA;
|
||||||
|
import net.schmizz.sshj.signature.SignatureECDSA;
|
||||||
import net.schmizz.sshj.signature.SignatureRSA;
|
import net.schmizz.sshj.signature.SignatureRSA;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CTR;
|
import net.schmizz.sshj.transport.cipher.AES128CTR;
|
||||||
@@ -56,11 +37,15 @@ import net.schmizz.sshj.transport.mac.HMACMD5;
|
|||||||
import net.schmizz.sshj.transport.mac.HMACMD596;
|
import net.schmizz.sshj.transport.mac.HMACMD596;
|
||||||
import net.schmizz.sshj.transport.mac.HMACSHA1;
|
import net.schmizz.sshj.transport.mac.HMACSHA1;
|
||||||
import net.schmizz.sshj.transport.mac.HMACSHA196;
|
import net.schmizz.sshj.transport.mac.HMACSHA196;
|
||||||
|
import net.schmizz.sshj.transport.mac.HMACSHA2256;
|
||||||
|
import net.schmizz.sshj.transport.mac.HMACSHA2512;
|
||||||
import net.schmizz.sshj.transport.random.BouncyCastleRandom;
|
import net.schmizz.sshj.transport.random.BouncyCastleRandom;
|
||||||
import net.schmizz.sshj.transport.random.JCERandom;
|
import net.schmizz.sshj.transport.random.JCERandom;
|
||||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -70,18 +55,23 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
* A {@link net.schmizz.sshj.Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
||||||
* BouncyCastle is in the classpath.
|
* BouncyCastle is in the classpath.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <ul> <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li> <li>{@link
|
* <ul>
|
||||||
* ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR}, {@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyExchangeFactories Key exchange}: {@link net.schmizz.sshj.transport.kex.DHG14}*, {@link net.schmizz.sshj.transport.kex.DHG1}</li>
|
||||||
* AES128CBC}, {@link AES192CBC}, {@link AES256CBC}, {@link AES192CBC}, {@link TripleDESCBC}, {@link BlowfishCBC}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCipherFactories Ciphers} [1]: {@link net.schmizz.sshj.transport.cipher.AES128CTR}, {@link net.schmizz.sshj.transport.cipher.AES192CTR}, {@link net.schmizz.sshj.transport.cipher.AES256CTR},
|
||||||
* <li>{@link ConfigImpl#setMACFactories MAC}: {@link HMACSHA1}, {@link HMACSHA196}, {@link HMACMD5}, {@link
|
* {@link
|
||||||
* HMACMD596}</li> <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li> <li>{@link
|
* net.schmizz.sshj.transport.cipher.AES128CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.AES256CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.TripleDESCBC}, {@link net.schmizz.sshj.transport.cipher.BlowfishCBC}</li>
|
||||||
* ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li> <li>{@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setMACFactories MAC}: {@link net.schmizz.sshj.transport.mac.HMACSHA1}, {@link net.schmizz.sshj.transport.mac.HMACSHA196}, {@link net.schmizz.sshj.transport.mac.HMACMD5}, {@link
|
||||||
* ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li> <li>{@link
|
* net.schmizz.sshj.transport.mac.HMACMD596}</li>
|
||||||
* ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link OpenSSHKeyFile}*</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
|
||||||
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li> </ul>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setSignatureFactories Signature}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link
|
||||||
|
* net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>
|
||||||
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
* [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.
|
* prevents using ciphers with strength greater than 128.
|
||||||
@@ -91,7 +81,7 @@ public class DefaultConfig
|
|||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private static final String VERSION = "SSHJ_0_6_0";
|
private static final String VERSION = "SSHJ_0_9_2";
|
||||||
|
|
||||||
public DefaultConfig() {
|
public DefaultConfig() {
|
||||||
setVersion(VERSION);
|
setVersion(VERSION);
|
||||||
@@ -103,6 +93,7 @@ public class DefaultConfig
|
|||||||
initCompressionFactories();
|
initCompressionFactories();
|
||||||
initMACFactories();
|
initMACFactories();
|
||||||
initSignatureFactories();
|
initSignatureFactories();
|
||||||
|
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
|
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
|
||||||
@@ -113,12 +104,13 @@ public class DefaultConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void initRandomFactory(boolean bouncyCastleRegistered) {
|
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) {
|
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
||||||
if (bouncyCastleRegistered) {
|
if (bouncyCastleRegistered) {
|
||||||
setFileKeyProviderFactories(new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory());
|
setFileKeyProviderFactories(new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory(), new PuTTYKeyFile.Factory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,12 +148,12 @@ public class DefaultConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void initSignatureFactories() {
|
protected void initSignatureFactories() {
|
||||||
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
setSignatureFactories(new SignatureECDSA.Factory(), new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initMACFactories() {
|
protected void initMACFactories() {
|
||||||
setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
|
setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
|
||||||
new HMACMD596.Factory());
|
new HMACMD596.Factory(), new HMACSHA2256.Factory(), new HMACSHA2512.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initCompressionFactories() {
|
protected void initCompressionFactories() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
@@ -46,6 +45,7 @@ import net.schmizz.sshj.userauth.UserAuth;
|
|||||||
import net.schmizz.sshj.userauth.UserAuthException;
|
import net.schmizz.sshj.userauth.UserAuthException;
|
||||||
import net.schmizz.sshj.userauth.UserAuthImpl;
|
import net.schmizz.sshj.userauth.UserAuthImpl;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
|
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
|
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
|
||||||
@@ -64,10 +64,11 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketAddress;
|
import java.net.ServerSocket;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -92,8 +93,8 @@ import java.util.List;
|
|||||||
* <em>A simple example:</em>
|
* <em>A simple example:</em>
|
||||||
* <p/>
|
* <p/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* client = new SSHClient();
|
* final SSHClient client = new SSHClient();
|
||||||
* client.initUserKnownHosts();
|
* client.loadKnownHosts();
|
||||||
* client.connect("hostname");
|
* client.connect("hostname");
|
||||||
* try {
|
* try {
|
||||||
* client.authPassword("username", "password");
|
* client.authPassword("username", "password");
|
||||||
@@ -103,8 +104,9 @@ import java.util.List;
|
|||||||
* cmd.join(1, TimeUnit.SECONDS);
|
* cmd.join(1, TimeUnit.SECONDS);
|
||||||
* } finally {
|
* } finally {
|
||||||
* session.close();
|
* session.close();
|
||||||
* } finally {
|
* }
|
||||||
* client.disconnect();
|
* } finally {
|
||||||
|
* client.disconnect();
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -142,9 +144,9 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public SSHClient(Config config) {
|
public SSHClient(Config config) {
|
||||||
super(DEFAULT_PORT);
|
super(DEFAULT_PORT);
|
||||||
this.trans = new TransportImpl(config);
|
this.trans = new TransportImpl(config, this);
|
||||||
this.auth = new UserAuthImpl(trans);
|
this.auth = new UserAuthImpl(trans);
|
||||||
this.conn = new ConnectionImpl(trans);
|
this.conn = new ConnectionImpl(trans, config.getKeepAliveProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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}.
|
* Authenticate {@code username} using the supplied {@code methods}.
|
||||||
*
|
*
|
||||||
@@ -185,7 +189,7 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public void auth(String username, AuthMethod... methods)
|
public void auth(String username, AuthMethod... methods)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
checkConnected();
|
||||||
auth(username, Arrays.<AuthMethod>asList(methods));
|
auth(username, Arrays.<AuthMethod>asList(methods));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,8 +204,17 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public void auth(String username, Iterable<AuthMethod> methods)
|
public void auth(String username, Iterable<AuthMethod> methods)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
checkConnected();
|
||||||
auth.authenticate(username, (Service) conn, methods);
|
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
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
||||||
throws UserAuthException,
|
throws UserAuthException, TransportException {
|
||||||
TransportException {
|
|
||||||
final List<AuthMethod> am = new LinkedList<AuthMethod>();
|
final List<AuthMethod> am = new LinkedList<AuthMethod>();
|
||||||
for (KeyProvider kp : keyProviders)
|
for (KeyProvider kp : keyProviders)
|
||||||
am.add(new AuthPublickey(kp));
|
am.add(new AuthPublickey(kp));
|
||||||
@@ -342,13 +354,14 @@ public class SSHClient
|
|||||||
public void authPublickey(String username, String... locations)
|
public void authPublickey(String username, String... locations)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
||||||
for (String loc : locations)
|
for (String loc : locations) {
|
||||||
try {
|
try {
|
||||||
log.debug("Attempting to load key from: {}", loc);
|
log.debug("Attempting to load key from: {}", loc);
|
||||||
keyProviders.add(loadKeys(loc));
|
keyProviders.add(loadKeys(loc));
|
||||||
} catch (IOException logged) {
|
} 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);
|
authPublickey(username, keyProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,10 +375,8 @@ public class SSHClient
|
|||||||
@Override
|
@Override
|
||||||
public void disconnect()
|
public void disconnect()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assert isConnected();
|
|
||||||
trans.disconnect();
|
trans.disconnect();
|
||||||
super.disconnect();
|
super.disconnect();
|
||||||
assert !isConnected();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the associated {@link Connection} instance. */
|
/** @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
|
* @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#getBanner() authentication banner}, whether authentication was at least {@link
|
||||||
* UserAuth#hadPartialSuccess() partially successful}, and any {@link UserAuth#getSavedExceptions() saved
|
* UserAuth#hadPartialSuccess() partially successful}.
|
||||||
* exceptions} that were ignored because there were more authentication method that could be tried.
|
|
||||||
*/
|
*/
|
||||||
public UserAuth getUserAuth() {
|
public UserAuth getUserAuth() {
|
||||||
return auth;
|
return auth;
|
||||||
@@ -475,9 +485,9 @@ public class SSHClient
|
|||||||
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
|
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final File loc = new File(location);
|
final File loc = new File(location);
|
||||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
|
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(loc);
|
||||||
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
final FileKeyProvider fkp =
|
||||||
.toString());
|
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||||
if (fkp == null)
|
if (fkp == null)
|
||||||
throw new SSHException("No provider available for " + format + " key file");
|
throw new SSHException("No provider available for " + format + " key file");
|
||||||
fkp.init(loc, passwordFinder);
|
fkp.init(loc, passwordFinder);
|
||||||
@@ -519,9 +529,9 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
|
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
|
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
|
||||||
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
final FileKeyProvider fkp =
|
||||||
.toString());
|
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||||
if (fkp == null)
|
if (fkp == null)
|
||||||
throw new SSHException("No provider available for " + format + " key file");
|
throw new SSHException("No provider available for " + format + " key file");
|
||||||
fkp.init(privateKey, publicKey, passwordFinder);
|
fkp.init(privateKey, publicKey, passwordFinder);
|
||||||
@@ -568,23 +578,21 @@ public class SSHClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link LocalPortForwarder} that will listen on {@code address} and forward incoming connections to the
|
* Create a {@link LocalPortForwarder} that will listen based on {@code parameters} using the bound
|
||||||
* server; which will further forward them to {@code host:port}.
|
* {@code serverSocket} and forward incoming connections to the server; which will further forward them to
|
||||||
|
* {@code host:port}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
||||||
* listening, this method just creates an instance.
|
* listening, this method just creates an instance.
|
||||||
*
|
*
|
||||||
* @param address defines where the {@link LocalPortForwarder} listens
|
* @param parameters parameters for the forwarding setup
|
||||||
* @param host hostname to which the server will forward
|
* @param serverSocket bound server socket
|
||||||
* @param port the port at {@code hostname} to which the server wil forward
|
|
||||||
*
|
*
|
||||||
* @return a {@link LocalPortForwarder}
|
* @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)
|
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
|
||||||
throws IOException {
|
ServerSocket serverSocket) {
|
||||||
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
|
return new LocalPortForwarder(conn, parameters, serverSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -609,7 +617,8 @@ public class SSHClient
|
|||||||
|
|
||||||
/** @return Instantiated {@link SCPFileTransfer} implementation. */
|
/** @return Instantiated {@link SCPFileTransfer} implementation. */
|
||||||
public SCPFileTransfer newSCPFileTransfer() {
|
public SCPFileTransfer newSCPFileTransfer() {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
|
checkAuthenticated();
|
||||||
return new SCPFileTransfer(this);
|
return new SCPFileTransfer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +630,8 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public SFTPClient newSFTPClient()
|
public SFTPClient newSFTPClient()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
|
checkAuthenticated();
|
||||||
return new SFTPClient(new SFTPEngine(this).init());
|
return new SFTPClient(new SFTPEngine(this).init());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,10 +648,10 @@ public class SSHClient
|
|||||||
@Override
|
@Override
|
||||||
public Session startSession()
|
public Session startSession()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
|
checkAuthenticated();
|
||||||
final SessionChannel sess = new SessionChannel(conn);
|
final SessionChannel sess = new SessionChannel(conn);
|
||||||
sess.open();
|
sess.open();
|
||||||
assert sess.isOpen();
|
|
||||||
return sess;
|
return sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,11 +691,10 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
protected void doKex()
|
protected void doKex()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
assert trans.isRunning();
|
checkConnected();
|
||||||
|
|
||||||
final long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
trans.doKex();
|
trans.doKex();
|
||||||
log.info("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
log.debug("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -699,4 +708,16 @@ public class SSHClient
|
|||||||
disconnect();
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,40 +12,19 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
import javax.net.ServerSocketFactory;
|
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
|
public abstract class SocketClient {
|
||||||
abstract class SocketClient {
|
|
||||||
|
|
||||||
private final int defaultPort;
|
private final int defaultPort;
|
||||||
|
|
||||||
@@ -54,7 +33,6 @@ abstract class SocketClient {
|
|||||||
private OutputStream output;
|
private OutputStream output;
|
||||||
|
|
||||||
private SocketFactory socketFactory = SocketFactory.getDefault();
|
private SocketFactory socketFactory = SocketFactory.getDefault();
|
||||||
private ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault();
|
|
||||||
|
|
||||||
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
||||||
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||||
@@ -74,12 +52,25 @@ abstract class SocketClient {
|
|||||||
onConnect();
|
onConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connect(InetAddress host, int port, Proxy proxy)
|
||||||
|
throws IOException {
|
||||||
|
socket = new Socket(proxy);
|
||||||
|
socket.connect(new InetSocketAddress(host, port), connectTimeout);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
|
||||||
public void connect(String hostname, int port)
|
public void connect(String hostname, int port)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this.hostname = hostname;
|
this.hostname = hostname;
|
||||||
connect(InetAddress.getByName(hostname), port);
|
connect(InetAddress.getByName(hostname), port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connect(String hostname, int port, Proxy proxy)
|
||||||
|
throws IOException {
|
||||||
|
this.hostname = hostname;
|
||||||
|
connect(InetAddress.getByName(hostname), port, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
public void connect(InetAddress host, int port,
|
public void connect(InetAddress host, int port,
|
||||||
InetAddress localAddr, int localPort)
|
InetAddress localAddr, int localPort)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
@@ -106,6 +97,16 @@ abstract class SocketClient {
|
|||||||
connect(hostname, defaultPort);
|
connect(hostname, defaultPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connect(InetAddress host, Proxy proxy)
|
||||||
|
throws IOException {
|
||||||
|
connect(host, defaultPort, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(String hostname, Proxy proxy)
|
||||||
|
throws IOException {
|
||||||
|
connect(hostname, defaultPort, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
public void disconnect()
|
public void disconnect()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
@@ -158,17 +159,6 @@ abstract class SocketClient {
|
|||||||
return socketFactory;
|
return socketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerSocketFactory(ServerSocketFactory factory) {
|
|
||||||
if (factory == null)
|
|
||||||
serverSocketFactory = ServerSocketFactory.getDefault();
|
|
||||||
else
|
|
||||||
serverSocketFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerSocketFactory getServerSocketFactory() {
|
|
||||||
return serverSocketFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getConnectTimeout() {
|
public int getConnectTimeout() {
|
||||||
return connectTimeout;
|
return connectTimeout;
|
||||||
}
|
}
|
||||||
@@ -204,4 +194,4 @@ abstract class SocketClient {
|
|||||||
output = socket.getOutputStream();
|
output = socket.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
@@ -51,7 +31,7 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PlainBuffer
|
public static final class PlainBuffer
|
||||||
extends Buffer<PlainBuffer> {
|
extends Buffer<PlainBuffer> {
|
||||||
|
|
||||||
public PlainBuffer() {
|
public PlainBuffer() {
|
||||||
@@ -74,10 +54,15 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
/** The default size for a {@code Buffer} (256 bytes) */
|
/** The default size for a {@code Buffer} (256 bytes) */
|
||||||
public static final int DEFAULT_SIZE = 256;
|
public static final int DEFAULT_SIZE = 256;
|
||||||
|
|
||||||
|
/** 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) {
|
protected static int getNextPowerOf2(int i) {
|
||||||
int j = 1;
|
int j = 1;
|
||||||
while (j < i)
|
while (j < i) {
|
||||||
j <<= 1;
|
j <<= 1;
|
||||||
|
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
|
||||||
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,21 +15,25 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.*;
|
||||||
import java.security.Key;
|
import java.security.interfaces.*;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.interfaces.DSAPrivateKey;
|
|
||||||
import java.security.interfaces.DSAPublicKey;
|
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.security.spec.DSAPublicKeySpec;
|
import java.security.spec.DSAPublicKeySpec;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Type of key e.g. rsa, dsa */
|
/** Type of key e.g. rsa, dsa */
|
||||||
public enum KeyType {
|
public enum KeyType {
|
||||||
|
|
||||||
|
|
||||||
/** SSH identifier for RSA keys */
|
/** SSH identifier for RSA keys */
|
||||||
RSA("ssh-rsa") {
|
RSA("ssh-rsa") {
|
||||||
@Override
|
@Override
|
||||||
@@ -96,6 +100,89 @@ public enum KeyType {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** SSH identifier for ECDSA keys */
|
||||||
|
ECDSA("ecdsa-sha2-nistp256") {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
try {
|
||||||
|
// final String algo = buf.readString(); it has been already read
|
||||||
|
final String curveName = buf.readString();
|
||||||
|
final int keyLen = buf.readUInt32AsInt();
|
||||||
|
final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check
|
||||||
|
final byte[] x = new byte[(keyLen - 1) / 2];
|
||||||
|
final byte[] y = new byte[(keyLen - 1) / 2];
|
||||||
|
buf.readRawBytes(x);
|
||||||
|
buf.readRawBytes(y);
|
||||||
|
if(log.isDebugEnabled()) {
|
||||||
|
log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
|
||||||
|
type,
|
||||||
|
curveName,
|
||||||
|
keyLen,
|
||||||
|
x04,
|
||||||
|
Arrays.toString(x),
|
||||||
|
Arrays.toString(y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NISTP_CURVE.equals(curveName)) {
|
||||||
|
throw new GeneralSecurityException(String.format("Unknown curve %s", curveName));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger bigX = new BigInteger(1, x);
|
||||||
|
BigInteger bigY = new BigInteger(1, y);
|
||||||
|
|
||||||
|
X9ECParameters ecParams = NISTNamedCurves.getByName("p-256");
|
||||||
|
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY, false);
|
||||||
|
ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(),
|
||||||
|
ecParams.getG(), ecParams.getN());
|
||||||
|
ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec);
|
||||||
|
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
|
||||||
|
return keyFactory.generatePublic(publicSpec);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new GeneralSecurityException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
|
||||||
|
final ECPublicKey ecdsa = (ECPublicKey) pk;
|
||||||
|
final java.security.spec.ECPoint point = ecdsa.getW();
|
||||||
|
final byte[] x = trimStartingZeros(point.getAffineX().toByteArray());
|
||||||
|
final byte[] y = trimStartingZeros(point.getAffineY().toByteArray());
|
||||||
|
|
||||||
|
buf.putString(sType)
|
||||||
|
.putString(NISTP_CURVE)
|
||||||
|
.putUInt32(1 + x.length + y.length)
|
||||||
|
.putRawBytes(new byte[] { (byte) 0x04 })
|
||||||
|
.putRawBytes(x)
|
||||||
|
.putRawBytes(y)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isMyType(Key key) {
|
||||||
|
return ("ECDSA".equals(key.getAlgorithm()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] trimStartingZeros(byte[] in) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < in.length; i++) {
|
||||||
|
if (in[i] != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final byte[] out = new byte[in.length - i];
|
||||||
|
System.arraycopy(in, i, out, 0, out.length);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** Unrecognized */
|
/** Unrecognized */
|
||||||
UNKNOWN("unknown") {
|
UNKNOWN("unknown") {
|
||||||
@Override
|
@Override
|
||||||
@@ -113,10 +200,11 @@ public enum KeyType {
|
|||||||
protected boolean isMyType(Key key) {
|
protected boolean isMyType(Key key) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static final String NISTP_CURVE = "nistp256";
|
||||||
|
|
||||||
protected final String sType;
|
protected final String sType;
|
||||||
|
|
||||||
private KeyType(String type) {
|
private KeyType(String type) {
|
||||||
@@ -149,4 +237,4 @@ public enum KeyType {
|
|||||||
return sType;
|
return sType;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,32 +12,12 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class SSHPacket
|
public final class SSHPacket
|
||||||
extends Buffer<SSHPacket> {
|
extends Buffer<SSHPacket> {
|
||||||
|
|
||||||
public SSHPacket() {
|
public SSHPacket() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
@@ -62,11 +42,11 @@ public class SecurityUtils {
|
|||||||
public void run()
|
public void run()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
||||||
LOG.info("Trying to register BouncyCastle as a JCE provider");
|
LOG.debug("Trying to register BouncyCastle as a JCE provider");
|
||||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||||
MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
|
MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
|
||||||
KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
|
KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
|
||||||
LOG.info("Registration succeeded");
|
LOG.info("BouncyCastle registration succeeded");
|
||||||
} else
|
} else
|
||||||
LOG.info("BouncyCastle already registered as a JCE provider");
|
LOG.info("BouncyCastle already registered as a JCE provider");
|
||||||
securityProvider = BOUNCY_CASTLE;
|
securityProvider = BOUNCY_CASTLE;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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);
|
log.debug("Done copying from {}", in);
|
||||||
doneEvent.set();
|
doneEvent.set();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
log.error("In pipe from {} to {}: " + ioe.toString(), in, out);
|
log.error("In pipe from {} to {}: {}", in, out, ioe);
|
||||||
doneEvent.deliverError(ioe);
|
doneEvent.deliverError(ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ public class StreamCopier {
|
|||||||
|
|
||||||
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
||||||
final double sizeKiB = count / 1024.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)", sizeKiB, timeSeconds, (sizeKiB / timeSeconds));
|
||||||
|
|
||||||
if (length != -1 && read == -1)
|
if (length != -1 && read == -1)
|
||||||
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
|
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
|
||||||
@@ -154,4 +154,4 @@ public class StreamCopier {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj.connection;
|
package net.schmizz.sshj.connection;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.keepalive.KeepAlive;
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
import net.schmizz.sshj.connection.channel.Channel;
|
import net.schmizz.sshj.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.connection.channel.OpenFailException;
|
import net.schmizz.sshj.connection.channel.OpenFailException;
|
||||||
@@ -125,29 +126,34 @@ public interface Connection {
|
|||||||
void setMaxPacketSize(int maxPacketSize);
|
void setMaxPacketSize(int maxPacketSize);
|
||||||
|
|
||||||
/** @return the size for the local window this connection recommends to any {@link Channel}'s that ask for it. */
|
/** @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.
|
* 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
|
* @param windowSize window size in bytes
|
||||||
*/
|
*/
|
||||||
void setWindowSize(int windowSize);
|
void setWindowSize(long windowSize);
|
||||||
|
|
||||||
/** @return the associated {@link Transport}. */
|
/** @return the associated {@link Transport}. */
|
||||||
Transport getTransport();
|
Transport getTransport();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the {@code timeout} in seconds that this connection uses for blocking operations and recommends to any
|
* @return the {@code timeout} in milliseconds that this connection uses for blocking operations and recommends to
|
||||||
* {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
|
* 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}
|
* Set the {@code timeout} this connection uses for blocking operations and recommends to any {@link Channel other}
|
||||||
* {@link ForwardedChannelOpener classes} that ask for it.
|
* {@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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The configured {@link net.schmizz.keepalive.KeepAlive} mechanism.
|
||||||
|
*/
|
||||||
|
KeepAlive getKeepAlive();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,8 @@ package net.schmizz.sshj.connection;
|
|||||||
|
|
||||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.keepalive.KeepAlive;
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.AbstractService;
|
import net.schmizz.sshj.AbstractService;
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.Buffer;
|
||||||
import net.schmizz.sshj.common.DisconnectReason;
|
import net.schmizz.sshj.common.DisconnectReason;
|
||||||
@@ -51,21 +53,30 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
private final Queue<Promise<SSHPacket, ConnectionException>> globalReqPromises = new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
private final Queue<Promise<SSHPacket, ConnectionException>> globalReqPromises = new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
||||||
|
|
||||||
private int windowSize = 2048 * 1024;
|
/** {@code keep-alive} mechanism */
|
||||||
|
private final KeepAlive keepAlive;
|
||||||
|
|
||||||
|
private long windowSize = 2048 * 1024;
|
||||||
private int maxPacketSize = 32 * 1024;
|
private int maxPacketSize = 32 * 1024;
|
||||||
|
|
||||||
|
private volatile int timeoutMs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create with an associated {@link Transport}.
|
* Create with an associated {@link Transport}.
|
||||||
*
|
*
|
||||||
|
* @param config the ssh config
|
||||||
* @param trans transport layer
|
* @param trans transport layer
|
||||||
|
* @param keepAlive
|
||||||
*/
|
*/
|
||||||
public ConnectionImpl(Transport trans) {
|
public ConnectionImpl(Transport trans, KeepAliveProvider keepAlive) {
|
||||||
super("ssh-connection", trans);
|
super("ssh-connection", trans);
|
||||||
|
timeoutMs = trans.getTimeoutMs();
|
||||||
|
this.keepAlive = keepAlive.provide(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attach(Channel chan) {
|
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);
|
channels.put(chan.getID(), chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +92,7 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forget(Channel chan) {
|
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());
|
channels.remove(chan.getID());
|
||||||
synchronized (internalSynchronizer) {
|
synchronized (internalSynchronizer) {
|
||||||
if (channels.isEmpty())
|
if (channels.isEmpty())
|
||||||
@@ -91,13 +102,13 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forget(ForwardedChannelOpener opener) {
|
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());
|
openers.remove(opener.getChannelType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attach(ForwardedChannelOpener opener) {
|
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);
|
openers.put(opener.getChannelType(), opener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +170,12 @@ public class ConnectionImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWindowSize() {
|
public long getWindowSize() {
|
||||||
return windowSize;
|
return windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWindowSize(int windowSize) {
|
public void setWindowSize(long windowSize) {
|
||||||
this.windowSize = windowSize;
|
this.windowSize = windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +198,7 @@ public class ConnectionImpl
|
|||||||
byte[] specifics)
|
byte[] specifics)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
synchronized (globalReqPromises) {
|
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)
|
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
|
||||||
.putBoolean(wantReply)
|
.putBoolean(wantReply)
|
||||||
.putRawBytes(specifics));
|
.putRawBytes(specifics));
|
||||||
@@ -247,8 +258,24 @@ public class ConnectionImpl
|
|||||||
ErrorDeliveryUtil.alertPromises(error, globalReqPromises);
|
ErrorDeliveryUtil.alertPromises(error, globalReqPromises);
|
||||||
globalReqPromises.clear();
|
globalReqPromises.clear();
|
||||||
}
|
}
|
||||||
|
keepAlive.interrupt();
|
||||||
ErrorNotifiable.Util.alertAll(error, channels.values());
|
ErrorNotifiable.Util.alertAll(error, channels.values());
|
||||||
channels.clear();
|
channels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimeoutMs(int timeoutMs) {
|
||||||
|
this.timeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeoutMs() {
|
||||||
|
return timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeepAlive getKeepAlive() {
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
@@ -53,14 +33,16 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public abstract class AbstractChannel
|
public abstract class AbstractChannel
|
||||||
implements Channel {
|
implements Channel {
|
||||||
|
|
||||||
|
private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
|
||||||
|
|
||||||
/** Logger */
|
/** Logger */
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@@ -76,18 +58,15 @@ public abstract class AbstractChannel
|
|||||||
/** Remote recipient ID */
|
/** Remote recipient ID */
|
||||||
private int recipient;
|
private int recipient;
|
||||||
|
|
||||||
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new ConcurrentLinkedQueue<Event<ConnectionException>>();
|
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
|
||||||
|
|
||||||
/* The lock used by to create the open & close events */
|
/* 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 */
|
/** Channel open event */
|
||||||
protected final Event<ConnectionException> open;
|
protected final Event<ConnectionException> openEvent;
|
||||||
/** Channel close event */
|
/** Channel close event */
|
||||||
protected final Event<ConnectionException> close;
|
protected final Event<ConnectionException> closeEvent;
|
||||||
|
/** Whether we have already sent a CHANNEL_CLOSE request to the server */
|
||||||
/* Access to these fields should be synchronized using this object */
|
|
||||||
private boolean eofSent;
|
|
||||||
private boolean eofGot;
|
|
||||||
private boolean closeRequested;
|
private boolean closeRequested;
|
||||||
|
|
||||||
/** Local window */
|
/** Local window */
|
||||||
@@ -112,15 +91,15 @@ public abstract class AbstractChannel
|
|||||||
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
|
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
|
||||||
in = new ChannelInputStream(this, trans, lwin);
|
in = new ChannelInputStream(this, trans, lwin);
|
||||||
|
|
||||||
open = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, lock);
|
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock);
|
||||||
close = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, lock);
|
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;
|
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);
|
out = new ChannelOutputStream(this, trans, rwin);
|
||||||
log.info("Initialized - {}", this);
|
log.debug("Initialized - {}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,7 +123,7 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLocalWinSize() {
|
public long getLocalWinSize() {
|
||||||
return lwin.getSize();
|
return lwin.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +143,7 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRemoteWinSize() {
|
public long getRemoteWinSize() {
|
||||||
return rwin.getSize();
|
return rwin.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +197,7 @@ public abstract class AbstractChannel
|
|||||||
|
|
||||||
private void gotClose()
|
private void gotClose()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Got close");
|
log.debug("Got close");
|
||||||
try {
|
try {
|
||||||
closeAllStreams();
|
closeAllStreams();
|
||||||
sendClose();
|
sendClose();
|
||||||
@@ -236,7 +215,7 @@ public abstract class AbstractChannel
|
|||||||
public void notifyError(SSHException error) {
|
public void notifyError(SSHException error) {
|
||||||
log.debug("Channel #{} got notified of {}", getID(), error.toString());
|
log.debug("Channel #{} got notified of {}", getID(), error.toString());
|
||||||
|
|
||||||
ErrorDeliveryUtil.alertEvents(error, open, close);
|
ErrorDeliveryUtil.alertEvents(error, openEvent, closeEvent);
|
||||||
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
|
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
|
||||||
|
|
||||||
in.notifyError(error);
|
in.notifyError(error);
|
||||||
@@ -254,49 +233,53 @@ public abstract class AbstractChannel
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
lock.lock();
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
try {
|
if (isOpen()) {
|
||||||
sendClose();
|
try {
|
||||||
} catch (TransportException e) {
|
sendClose();
|
||||||
if (!close.inError())
|
} catch (TransportException e) {
|
||||||
throw e;
|
if (!closeEvent.inError())
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
closeEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
close.await(conn.getTimeout(), TimeUnit.SECONDS);
|
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join()
|
public void join()
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
close.await();
|
closeEvent.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join(int timeout, TimeUnit unit)
|
public void join(long timeout, TimeUnit unit)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
close.await(timeout, unit);
|
closeEvent.await(timeout, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void sendClose()
|
protected void sendClose()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
if (!closeRequested) {
|
if (!closeRequested) {
|
||||||
log.info("Sending close");
|
log.debug("Sending close");
|
||||||
trans.write(newBuffer(Message.CHANNEL_CLOSE));
|
trans.write(newBuffer(Message.CHANNEL_CLOSE));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
closeRequested = true;
|
closeRequested = true;
|
||||||
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isOpen() {
|
public boolean isOpen() {
|
||||||
lock.lock();
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
return open.isSet() && !close.isSet() && !closeRequested;
|
return openEvent.isSet() && !closeEvent.isSet() && !closeRequested;
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,25 +292,25 @@ public abstract class AbstractChannel
|
|||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
log.info("Got chan request for `{}`", reqType);
|
log.debug("Got chan request for `{}`", reqType);
|
||||||
handleRequest(reqType, buf);
|
handleRequest(reqType, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotWindowAdjustment(SSHPacket buf)
|
private void gotWindowAdjustment(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
final int howMuch;
|
final long howMuch;
|
||||||
try {
|
try {
|
||||||
howMuch = buf.readUInt32AsInt();
|
howMuch = buf.readUInt32();
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
log.info("Received window adjustment for {} bytes", howMuch);
|
log.debug("Received window adjustment for {} bytes", howMuch);
|
||||||
rwin.expand(howMuch);
|
rwin.expand(howMuch);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void finishOff() {
|
protected void finishOff() {
|
||||||
conn.forget(this);
|
conn.forget(this);
|
||||||
close.set();
|
closeEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void gotExtendedData(SSHPacket buf)
|
protected void gotExtendedData(SSHPacket buf)
|
||||||
@@ -367,43 +350,44 @@ public abstract class AbstractChannel
|
|||||||
protected Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
protected Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
||||||
Buffer.PlainBuffer reqSpecific)
|
Buffer.PlainBuffer reqSpecific)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Sending channel request for `{}`", reqType);
|
log.debug("Sending channel request for `{}`", reqType);
|
||||||
trans.write(
|
synchronized (chanReqResponseEvents) {
|
||||||
newBuffer(Message.CHANNEL_REQUEST)
|
trans.write(
|
||||||
.putString(reqType)
|
newBuffer(Message.CHANNEL_REQUEST)
|
||||||
.putBoolean(wantReply)
|
.putString(reqType)
|
||||||
.putBuffer(reqSpecific)
|
.putBoolean(wantReply)
|
||||||
);
|
.putBuffer(reqSpecific)
|
||||||
|
);
|
||||||
|
|
||||||
Event<ConnectionException> responseEvent = null;
|
Event<ConnectionException> responseEvent = null;
|
||||||
if (wantReply) {
|
if (wantReply) {
|
||||||
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
|
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
|
||||||
ConnectionException.chainer);
|
ConnectionException.chainer);
|
||||||
chanReqResponseEvents.add(responseEvent);
|
chanReqResponseEvents.add(responseEvent);
|
||||||
|
}
|
||||||
|
return responseEvent;
|
||||||
}
|
}
|
||||||
return responseEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotResponse(boolean success)
|
private void gotResponse(boolean success)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
synchronized (chanReqResponseEvents) {
|
||||||
if (responseEvent != null) {
|
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
||||||
if (success)
|
if (responseEvent != null) {
|
||||||
responseEvent.set();
|
if (success)
|
||||||
else
|
responseEvent.set();
|
||||||
responseEvent.deliverError(new ConnectionException("Request failed"));
|
else
|
||||||
} else
|
responseEvent.deliverError(new ConnectionException("Request failed"));
|
||||||
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
} else
|
||||||
"Received response to channel request when none was requested");
|
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
||||||
|
"Received response to channel request when none was requested");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void gotEOF()
|
private void gotEOF()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Got EOF");
|
log.debug("Got EOF");
|
||||||
eofGot = true;
|
|
||||||
eofInputStreams();
|
eofInputStreams();
|
||||||
if (eofSent)
|
|
||||||
sendClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when EOF has been received. Subclasses can override but must call super. */
|
/** Called when EOF has been received. Subclasses can override but must call super. */
|
||||||
@@ -411,22 +395,6 @@ public abstract class AbstractChannel
|
|||||||
in.eof();
|
in.eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void sendEOF()
|
|
||||||
throws TransportException {
|
|
||||||
try {
|
|
||||||
if (!closeRequested && !eofSent) {
|
|
||||||
log.info("Sending EOF");
|
|
||||||
trans.write(newBuffer(Message.CHANNEL_EOF));
|
|
||||||
if (eofGot)
|
|
||||||
sendClose();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
eofSent = true;
|
|
||||||
out.setClosed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "< " + type + " channel: id=" + id + ", recipient=" + recipient + ", localWin=" + lwin + ", remoteWin="
|
return "< " + type + " channel: id=" + id + ", recipient=" + recipient + ", localWin=" + lwin + ", remoteWin="
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -99,7 +99,7 @@ public interface Channel
|
|||||||
int getLocalMaxPacketSize();
|
int getLocalMaxPacketSize();
|
||||||
|
|
||||||
/** @return the current local window size. */
|
/** @return the current local window size. */
|
||||||
int getLocalWinSize();
|
long getLocalWinSize();
|
||||||
|
|
||||||
/** @return an {@code OutputStream} for this channel. */
|
/** @return an {@code OutputStream} for this channel. */
|
||||||
OutputStream getOutputStream();
|
OutputStream getOutputStream();
|
||||||
@@ -111,7 +111,7 @@ public interface Channel
|
|||||||
int getRemoteMaxPacketSize();
|
int getRemoteMaxPacketSize();
|
||||||
|
|
||||||
/** @return the current remote window size. */
|
/** @return the current remote window size. */
|
||||||
int getRemoteWinSize();
|
long getRemoteWinSize();
|
||||||
|
|
||||||
/** @return the channel type identifier. */
|
/** @return the channel type identifier. */
|
||||||
String getType();
|
String getType();
|
||||||
@@ -119,15 +119,6 @@ public interface Channel
|
|||||||
/** @return whether the channel is open. */
|
/** @return whether the channel is open. */
|
||||||
boolean isOpen();
|
boolean isOpen();
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an EOF message to the server for this channel; indicating that no more data will be sent by us. The {@code
|
|
||||||
* OutputStream} for this channel will be closed and no longer usable.
|
|
||||||
*
|
|
||||||
* @throws TransportException if there is an error sending the EOF message
|
|
||||||
*/
|
|
||||||
void sendEOF()
|
|
||||||
throws TransportException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
||||||
* read from that stream. This is useful e.g. when a remote command produces a lot of output that would fill the
|
* read from that stream. This is useful e.g. when a remote command produces a lot of output that would fill the
|
||||||
@@ -140,7 +131,7 @@ public interface Channel
|
|||||||
void join()
|
void join()
|
||||||
throws ConnectionException;
|
throws ConnectionException;
|
||||||
|
|
||||||
void join(int timeout, TimeUnit unit)
|
void join(long timeout, TimeUnit unit)
|
||||||
throws ConnectionException;
|
throws ConnectionException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,28 +12,7 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.Buffer;
|
||||||
@@ -159,9 +138,9 @@ public final class ChannelInputStream
|
|||||||
private void checkWindow()
|
private void checkWindow()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
synchronized (win) {
|
synchronized (win) {
|
||||||
final int adjustment = win.neededAdjustment();
|
final long adjustment = win.neededAdjustment();
|
||||||
if (adjustment > 0) {
|
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)
|
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
|
||||||
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
||||||
win.expand(adjustment);
|
win.expand(adjustment);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,35 +12,17 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
import net.schmizz.sshj.common.ErrorNotifiable;
|
||||||
import net.schmizz.sshj.common.Message;
|
import net.schmizz.sshj.common.Message;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -56,26 +38,99 @@ public final class ChannelOutputStream
|
|||||||
private final Channel chan;
|
private final Channel chan;
|
||||||
private final Transport trans;
|
private final Transport trans;
|
||||||
private final Window.Remote win;
|
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 final byte[] b = new byte[1];
|
||||||
private int bufferLength;
|
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
private SSHException error;
|
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, true);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
final int n = Math.min(len, win.getMaxPacketSize() - bufferSize);
|
||||||
|
packet.putRawBytes(data, off, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flush(boolean canAwaitExpansion)
|
||||||
|
throws TransportException, ConnectionException {
|
||||||
|
return flush(packet.wpos() - dataOffset, canAwaitExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flush(int bufferSize, boolean canAwaitExpansion)
|
||||||
|
throws TransportException, ConnectionException {
|
||||||
|
while (bufferSize > 0) {
|
||||||
|
|
||||||
|
long remoteWindowSize = win.getSize();
|
||||||
|
if (remoteWindowSize == 0) {
|
||||||
|
if (canAwaitExpansion) {
|
||||||
|
remoteWindowSize = win.awaitExpansion(remoteWindowSize);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
|
public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
|
||||||
this.chan = chan;
|
this.chan = chan;
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
this.win = win;
|
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
|
@Override
|
||||||
@@ -86,19 +141,13 @@ public final class ChannelOutputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(byte[] data, int off, int len)
|
public synchronized void write(final byte[] data, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
|
final int n = buffer.write(data, off, len);
|
||||||
if (x <= 0) {
|
off += n;
|
||||||
flush();
|
len -= n;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
buffer.putRawBytes(data, off, x);
|
|
||||||
bufferLength += x;
|
|
||||||
off += x;
|
|
||||||
len -= x;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,55 +156,40 @@ public final class ChannelOutputStream
|
|||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void checkClose()
|
private void checkClose()
|
||||||
throws SSHException {
|
throws SSHException {
|
||||||
if (closed)
|
if (closed) {
|
||||||
if (error != null)
|
if (error != null)
|
||||||
throw error;
|
throw error;
|
||||||
else
|
else
|
||||||
throw new ConnectionException("Stream closed");
|
throw new ConnectionException("Stream closed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close()
|
public synchronized void close()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!closed)
|
if (!closed) {
|
||||||
try {
|
try {
|
||||||
flush();
|
buffer.flush(false);
|
||||||
chan.sendEOF();
|
trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
|
||||||
} finally {
|
} finally {
|
||||||
setClosed();
|
closed = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Override
|
||||||
public synchronized void flush()
|
public synchronized void flush()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
|
buffer.flush(true);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,4 +197,4 @@ public final class ChannelOutputStream
|
|||||||
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
|
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 final int maxPacketSize;
|
||||||
|
|
||||||
protected int size;
|
protected long size;
|
||||||
|
|
||||||
public Window(int initialWinSize, int maxPacketSize) {
|
public Window(long initialWinSize, int maxPacketSize) {
|
||||||
size = initialWinSize;
|
size = initialWinSize;
|
||||||
this.maxPacketSize = maxPacketSize;
|
this.maxPacketSize = maxPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expand(int inc) {
|
public void expand(long inc) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
log.debug("Increasing by {} up to {}", inc, size);
|
|
||||||
size += inc;
|
size += inc;
|
||||||
|
log.debug("Increasing by {} up to {}", inc, size);
|
||||||
lock.notifyAll();
|
lock.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,15 +47,17 @@ public abstract class Window {
|
|||||||
return maxPacketSize;
|
return maxPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public long getSize() {
|
||||||
return size;
|
synchronized (lock) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consume(int dec)
|
public void consume(long dec)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
log.debug("Consuming by " + dec + " down to " + size);
|
|
||||||
size -= dec;
|
size -= dec;
|
||||||
|
log.debug("Consuming by {} down to {}", dec, size);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
throw new ConnectionException("Window consumed to below 0");
|
throw new ConnectionException("Window consumed to below 0");
|
||||||
}
|
}
|
||||||
@@ -70,29 +72,29 @@ public abstract class Window {
|
|||||||
public static final class Remote
|
public static final class Remote
|
||||||
extends Window {
|
extends Window {
|
||||||
|
|
||||||
public Remote(int initialWinSize, int maxPacketSize) {
|
public Remote(long initialWinSize, int maxPacketSize) {
|
||||||
super(initialWinSize, maxPacketSize);
|
super(initialWinSize, maxPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitAndConsume(int howMuch)
|
public long awaitExpansion(long was)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
while (size < howMuch) {
|
while (size <= was) {
|
||||||
log.debug("Waiting, need window space for {} bytes", howMuch);
|
log.debug("Waiting, need size to grow from {} bytes", was);
|
||||||
try {
|
try {
|
||||||
lock.wait();
|
lock.wait();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
throw new ConnectionException(ie);
|
throw new ConnectionException(ie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
consume(howMuch);
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consume(int howMuch) {
|
public void consume(long howMuch) {
|
||||||
try {
|
try {
|
||||||
super.consume(howMuch);
|
super.consume(howMuch);
|
||||||
} catch (ConnectionException e) {
|
} catch (ConnectionException e) { // It's a bug if we consume more than remote allowed
|
||||||
throw new SSHRuntimeException(e);
|
throw new SSHRuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,18 +105,18 @@ public abstract class Window {
|
|||||||
public static final class Local
|
public static final class Local
|
||||||
extends Window {
|
extends Window {
|
||||||
|
|
||||||
private final int initialSize;
|
private final long initialSize;
|
||||||
private final int threshold;
|
private final long threshold;
|
||||||
|
|
||||||
public Local(int initialWinSize, int maxPacketSize) {
|
public Local(long initialWinSize, int maxPacketSize) {
|
||||||
super(initialWinSize, maxPacketSize);
|
super(initialWinSize, maxPacketSize);
|
||||||
this.initialSize = initialWinSize;
|
this.initialSize = initialWinSize;
|
||||||
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int neededAdjustment() {
|
public long neededAdjustment() {
|
||||||
synchronized (lock) {
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
@@ -65,23 +45,23 @@ public abstract class AbstractDirectChannel
|
|||||||
public void open()
|
public void open()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
trans.write(buildOpenReq());
|
trans.write(buildOpenReq());
|
||||||
open.await(conn.getTimeout(), TimeUnit.SECONDS);
|
openEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotOpenConfirmation(SSHPacket buf)
|
private void gotOpenConfirmation(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
try {
|
try {
|
||||||
init(buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt());
|
init(buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32());
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
open.set();
|
openEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotOpenFailure(SSHPacket buf)
|
private void gotOpenFailure(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
try {
|
try {
|
||||||
open.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
openEvent.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.SSHPacket;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
import net.schmizz.sshj.connection.Connection;
|
import net.schmizz.sshj.connection.Connection;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.net.ServerSocketFactory;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class LocalPortForwarder {
|
public class LocalPortForwarder {
|
||||||
|
|
||||||
private class DirectTCPIPChannel
|
public static class Parameters {
|
||||||
extends AbstractDirectChannel {
|
|
||||||
|
|
||||||
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) {
|
public Parameters(String localHost, int localPort, String remoteHost, int remotePort) {
|
||||||
super(conn, "direct-tcpip");
|
this.localHost = localHost;
|
||||||
this.sock = sock;
|
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 {
|
throws IOException {
|
||||||
sock.setSendBufferSize(getLocalMaxPacketSize());
|
socket.setSendBufferSize(getLocalMaxPacketSize());
|
||||||
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
|
socket.setReceiveBufferSize(getRemoteMaxPacketSize());
|
||||||
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), getOutputStream())
|
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream())
|
||||||
.bufSize(getRemoteMaxPacketSize())
|
.bufSize(getRemoteMaxPacketSize())
|
||||||
.spawnDaemon("soc2chan");
|
.spawnDaemon("soc2chan");
|
||||||
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), sock.getOutputStream())
|
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream())
|
||||||
.bufSize(getLocalMaxPacketSize())
|
.bufSize(getLocalMaxPacketSize())
|
||||||
.spawnDaemon("chan2soc");
|
.spawnDaemon("chan2soc");
|
||||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, sock);
|
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SSHPacket buildOpenReq() {
|
protected SSHPacket buildOpenReq() {
|
||||||
return super.buildOpenReq()
|
return super.buildOpenReq()
|
||||||
.putString(host)
|
.putString(parameters.getRemoteHost())
|
||||||
.putUInt32(port)
|
.putUInt32(parameters.getRemotePort())
|
||||||
.putString(ss.getInetAddress().getHostAddress())
|
.putString(parameters.getLocalHost())
|
||||||
.putUInt32(ss.getLocalPort());
|
.putUInt32(parameters.getLocalPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log = LoggerFactory.getLogger(LocalPortForwarder.class);
|
||||||
|
|
||||||
private final Connection conn;
|
private final Connection conn;
|
||||||
private final ServerSocket ss;
|
private final Parameters parameters;
|
||||||
private final String host;
|
private final ServerSocket serverSocket;
|
||||||
private final int port;
|
|
||||||
|
|
||||||
/**
|
public LocalPortForwarder(Connection conn, Parameters parameters, 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 {
|
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.host = host;
|
this.parameters = parameters;
|
||||||
this.port = port;
|
this.serverSocket = serverSocket;
|
||||||
this.ss = ssf.createServerSocket();
|
|
||||||
ss.setReceiveBufferSize(conn.getMaxPacketSize());
|
|
||||||
ss.bind(listeningAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the address to which this forwarder is bound for listening */
|
protected DirectTCPIPChannel openChannel(Socket socket)
|
||||||
public SocketAddress getListeningAddress() {
|
throws TransportException, ConnectionException {
|
||||||
return ss.getLocalSocketAddress();
|
final DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
|
||||||
|
chan.open();
|
||||||
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,16 +126,13 @@ public class LocalPortForwarder {
|
|||||||
*/
|
*/
|
||||||
public void listen()
|
public void listen()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
log.info("Listening on {}", ss.getLocalSocketAddress());
|
log.info("Listening on {}", serverSocket.getLocalSocketAddress());
|
||||||
Socket sock;
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
sock = ss.accept();
|
final Socket socket = serverSocket.accept();
|
||||||
log.info("Got connection from {}", sock.getRemoteSocketAddress());
|
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
|
||||||
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, sock);
|
openChannel(socket).start();
|
||||||
chan.open();
|
|
||||||
chan.start();
|
|
||||||
}
|
}
|
||||||
log.info("Interrupted!");
|
log.debug("Interrupted!");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -81,14 +80,6 @@ public interface Session
|
|||||||
void signal(Signal signal)
|
void signal(Signal signal)
|
||||||
throws TransportException;
|
throws TransportException;
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
String getOutputAsString()
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
String getErrorAsString()
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shell API. */
|
/** Shell API. */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
@@ -46,7 +26,6 @@ import net.schmizz.sshj.connection.ConnectionException;
|
|||||||
import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -59,13 +38,13 @@ public class SessionChannel
|
|||||||
|
|
||||||
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
|
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
|
||||||
|
|
||||||
private Integer exitStatus;
|
private volatile Integer exitStatus;
|
||||||
|
|
||||||
private Signal exitSignal;
|
private volatile Signal exitSignal;
|
||||||
private Boolean wasCoreDumped;
|
private volatile Boolean wasCoreDumped;
|
||||||
private String exitErrMsg;
|
private volatile String exitErrMsg;
|
||||||
|
|
||||||
private Boolean canDoFlowControl;
|
private volatile Boolean canDoFlowControl;
|
||||||
|
|
||||||
private boolean usedUp;
|
private boolean usedUp;
|
||||||
|
|
||||||
@@ -76,7 +55,7 @@ public class SessionChannel
|
|||||||
@Override
|
@Override
|
||||||
public void allocateDefaultPTY()
|
public void allocateDefaultPTY()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
allocatePTY("dummy", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,7 +71,7 @@ public class SessionChannel
|
|||||||
.putUInt32(width)
|
.putUInt32(width)
|
||||||
.putUInt32(height)
|
.putUInt32(height)
|
||||||
.putBytes(PTYMode.encode(modes))
|
.putBytes(PTYMode.encode(modes))
|
||||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,9 +97,9 @@ public class SessionChannel
|
|||||||
public Command exec(String command)
|
public Command exec(String command)
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkReuse();
|
checkReuse();
|
||||||
log.info("Will request to exec `{}`", command);
|
log.debug("Will request to exec `{}`", command);
|
||||||
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -176,14 +155,14 @@ public class SessionChannel
|
|||||||
.putString(authProto)
|
.putString(authProto)
|
||||||
.putString(authCookie)
|
.putString(authCookie)
|
||||||
.putUInt32(screen)
|
.putUInt32(screen)
|
||||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnvVar(String name, String value)
|
public void setEnvVar(String name, String value)
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -196,7 +175,7 @@ public class SessionChannel
|
|||||||
public Shell startShell()
|
public Shell startShell()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkReuse();
|
checkReuse();
|
||||||
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
|
sendChannelRequest("shell", true, null).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -207,7 +186,7 @@ public class SessionChannel
|
|||||||
checkReuse();
|
checkReuse();
|
||||||
log.info("Will request `{}` subsystem", name);
|
log.info("Will request `{}` subsystem", name);
|
||||||
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -255,18 +234,4 @@ public class SessionChannel
|
|||||||
throw new SSHRuntimeException("This session channel is all used up");
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
|
|
||||||
@@ -54,8 +34,9 @@ public abstract class AbstractForwardedChannel
|
|||||||
* First 2 args are standard; the others can be parsed from a CHANNEL_OPEN packet.
|
* 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,
|
protected AbstractForwardedChannel(Connection conn, String type,
|
||||||
int remoteMaxPacketSize, String origIP, int origPort) {
|
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||||
|
String origIP, int origPort) {
|
||||||
super(conn, type);
|
super(conn, type);
|
||||||
this.origIP = origIP;
|
this.origIP = origIP;
|
||||||
this.origPort = origPort;
|
this.origPort = origPort;
|
||||||
@@ -65,20 +46,20 @@ public abstract class AbstractForwardedChannel
|
|||||||
@Override
|
@Override
|
||||||
public void confirm()
|
public void confirm()
|
||||||
throws TransportException {
|
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!
|
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
||||||
conn.attach(this);
|
conn.attach(this);
|
||||||
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
|
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
|
||||||
.putUInt32(getID())
|
.putUInt32(getID())
|
||||||
.putUInt32(getLocalWinSize())
|
.putUInt32(getLocalWinSize())
|
||||||
.putUInt32(getLocalMaxPacketSize()));
|
.putUInt32(getLocalMaxPacketSize()));
|
||||||
open.set();
|
openEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reject(Reason reason, String message)
|
public void reject(Reason reason, String message)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Rejecting `{}` channel: {}", getType(), message);
|
log.debug("Rejecting `{}` channel: {}", getType(), message);
|
||||||
conn.sendOpenFailure(getRecipient(), reason, message);
|
conn.sendOpenFailure(getRecipient(), reason, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -127,7 +127,8 @@ public class RemotePortForwarder
|
|||||||
|
|
||||||
private final Forward fwd;
|
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) {
|
Forward fwd, String origIP, int origPort) {
|
||||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||||
this.fwd = fwd;
|
this.fwd = fwd;
|
||||||
@@ -200,7 +201,7 @@ public class RemotePortForwarder
|
|||||||
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
|
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
|
||||||
.getCompactData();
|
.getCompactData();
|
||||||
return conn.sendGlobalRequest(reqName, true, specifics)
|
return conn.sendGlobalRequest(reqName, true, specifics)
|
||||||
.retrieve(conn.getTimeout(), TimeUnit.SECONDS);
|
.retrieve(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the active forwards. */
|
/** @return the active forwards. */
|
||||||
@@ -217,7 +218,7 @@ public class RemotePortForwarder
|
|||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
final ForwardedTCPIPChannel chan;
|
final ForwardedTCPIPChannel chan;
|
||||||
try {
|
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()),
|
new Forward(buf.readString(), buf.readUInt32AsInt()),
|
||||||
buf.readString(), buf.readUInt32AsInt());
|
buf.readString(), buf.readUInt32AsInt());
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -44,7 +44,7 @@ public class SocketForwardingConnectListener
|
|||||||
@Override
|
@Override
|
||||||
public void gotConnect(Channel.Forwarded chan)
|
public void gotConnect(Channel.Forwarded chan)
|
||||||
throws IOException {
|
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();
|
final Socket sock = new Socket();
|
||||||
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
|
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
|
||||||
@@ -66,4 +66,4 @@ public class SocketForwardingConnectListener
|
|||||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
|
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 static final String TYPE = "x11";
|
||||||
|
|
||||||
public X11Channel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize, String origIP,
|
public X11Channel(Connection conn,
|
||||||
int origPort) {
|
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||||
|
String origIP, int origPort) {
|
||||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +59,7 @@ public class X11Forwarder
|
|||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
try {
|
try {
|
||||||
callListener(listener, new X11Channel(conn,
|
callListener(listener, new X11Channel(conn,
|
||||||
buf.readUInt32AsInt(),
|
buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
|
||||||
buf.readUInt32AsInt(), buf.readUInt32AsInt(),
|
|
||||||
buf.readString(), buf.readUInt32AsInt()));
|
buf.readString(), buf.readUInt32AsInt()));
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.sshj.common.SSHException;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -56,24 +58,25 @@ public class PacketReader
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
readIntoBuffer(lenBuf, 0, lenBuf.length);
|
readIntoBuffer(lenBuf, 0, lenBuf.length);
|
||||||
|
|
||||||
return (int) (lenBuf[0] << 24 & 0xff000000L
|
final long len = (lenBuf[0] << 24 & 0xff000000L
|
||||||
| lenBuf[1] << 16 & 0x00ff0000L
|
| lenBuf[1] << 16 & 0x00ff0000L
|
||||||
| lenBuf[2] << 8 & 0x0000ff00L
|
| lenBuf[2] << 8 & 0x0000ff00L
|
||||||
| lenBuf[3] & 0x000000ffL);
|
| lenBuf[3] & 0x000000ffL);
|
||||||
|
|
||||||
|
if (len > SFTPPacket.MAX_SIZE) {
|
||||||
|
throw new SSHException(String.format("Indicated packet length %d too large", len));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) len;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SFTPPacket<Response> readPacket()
|
public SFTPPacket<Response> readPacket()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int len = getPacketLength();
|
final int len = getPacketLength();
|
||||||
|
packet.clear();
|
||||||
packet.rpos(0);
|
|
||||||
packet.wpos(0);
|
|
||||||
|
|
||||||
packet.ensureCapacity(len);
|
packet.ensureCapacity(len);
|
||||||
readIntoBuffer(packet.array(), 0, len);
|
readIntoBuffer(packet.array(), 0, len);
|
||||||
|
|
||||||
packet.wpos(len);
|
packet.wpos(len);
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,8 +105,11 @@ public class PacketReader
|
|||||||
promise.deliver(resp);
|
promise.deliver(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expectResponseTo(Request req) {
|
public Promise<Response, SFTPException> expectResponseTo(long requestId) {
|
||||||
promises.put(req.getRequestID(), req.getResponsePromise());
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 class PathHelper {
|
||||||
|
|
||||||
|
public interface Canonicalizer {
|
||||||
|
|
||||||
|
String canonicalize(String path)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static final String DEFAULT_PATH_SEPARATOR = "/";
|
public static final String DEFAULT_PATH_SEPARATOR = "/";
|
||||||
|
|
||||||
private final SFTPEngine engine;
|
private final Canonicalizer canonicalizer;
|
||||||
private final String pathSep;
|
private final String pathSep;
|
||||||
|
|
||||||
private String dotDir;
|
private String dotDir;
|
||||||
|
|
||||||
public PathHelper(SFTPEngine engine, String pathSep) {
|
private synchronized String getDotDir() // cached
|
||||||
this.engine = engine;
|
throws IOException {
|
||||||
|
return (dotDir != null) ? dotDir : (dotDir = canonicalizer.canonicalize("."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PathHelper(Canonicalizer canonicalizer, String pathSep) {
|
||||||
|
this.canonicalizer = canonicalizer;
|
||||||
this.pathSep = pathSep;
|
this.pathSep = pathSep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,37 +59,33 @@ public class PathHelper {
|
|||||||
return new PathComponents(parent, name, pathSep);
|
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 {
|
throws IOException {
|
||||||
if (path.isEmpty() || path.equals("."))
|
if (path.equals(pathSep))
|
||||||
|
return getComponents("", "");
|
||||||
|
|
||||||
|
if (path.isEmpty() || path.equals(".") || path.equals("." + pathSep))
|
||||||
return getComponents(getDotDir());
|
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 (name.equals(".") || name.equals("..")) {
|
||||||
if (path.equals(".."))
|
return getComponents(canonicalizer.canonicalize(path));
|
||||||
return getComponents(canon(path));
|
} else {
|
||||||
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);
|
|
||||||
return getComponents(parent, name);
|
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 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,11 +20,12 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class RemoteDirectory
|
public class RemoteDirectory
|
||||||
extends RemoteResource {
|
extends RemoteResource {
|
||||||
|
|
||||||
public RemoteDirectory(Requester requester, String path, String handle) {
|
public RemoteDirectory(Requester requester, String path, byte[] handle) {
|
||||||
super(requester, path, handle);
|
super(requester, path, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +34,8 @@ public class RemoteDirectory
|
|||||||
List<RemoteResourceInfo> rri = new LinkedList<RemoteResourceInfo>();
|
List<RemoteResourceInfo> rri = new LinkedList<RemoteResourceInfo>();
|
||||||
loop:
|
loop:
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
Response res = requester.doRequest(newRequest(PacketType.READDIR));
|
final Response res = requester.request(newRequest(PacketType.READDIR))
|
||||||
|
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
switch (res.getType()) {
|
switch (res.getType()) {
|
||||||
|
|
||||||
case NAME:
|
case NAME:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,32 +15,30 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
import net.schmizz.sshj.sftp.Response.StatusCode;
|
import net.schmizz.sshj.sftp.Response.StatusCode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class RemoteFile
|
public class RemoteFile
|
||||||
extends RemoteResource {
|
extends RemoteResource {
|
||||||
|
|
||||||
public RemoteFile(Requester requester, String path, String handle) {
|
public RemoteFile(Requester requester, String path, byte[] handle) {
|
||||||
super(requester, path, handle);
|
super(requester, path, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteFileInputStream getInputStream() {
|
|
||||||
return new RemoteFileInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteFileOutputStream getOutputStream() {
|
|
||||||
return new RemoteFileOutputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileAttributes fetchAttributes()
|
public FileAttributes fetchAttributes()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return requester.doRequest(newRequest(PacketType.FSTAT))
|
return requester.request(newRequest(PacketType.FSTAT))
|
||||||
.ensurePacketTypeIs(PacketType.ATTRS)
|
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
|
||||||
.readFileAttributes();
|
.ensurePacketTypeIs(PacketType.ATTRS)
|
||||||
|
.readFileAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long length()
|
public long length()
|
||||||
@@ -55,7 +53,17 @@ public class RemoteFile
|
|||||||
|
|
||||||
public int read(long fileOffset, byte[] to, int offset, int len)
|
public int read(long fileOffset, byte[] to, int offset, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Response res = requester.doRequest(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
|
final Response res = asyncRead(fileOffset, len).retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
|
return checkReadResponse(res, to, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Promise<Response, SFTPException> asyncRead(long fileOffset, int len)
|
||||||
|
throws IOException {
|
||||||
|
return requester.request(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int checkReadResponse(Response res, byte[] to, int offset)
|
||||||
|
throws Buffer.BufferException, SFTPException {
|
||||||
switch (res.getType()) {
|
switch (res.getType()) {
|
||||||
case DATA:
|
case DATA:
|
||||||
int recvLen = res.readUInt32AsInt();
|
int recvLen = res.readUInt32AsInt();
|
||||||
@@ -73,23 +81,34 @@ public class RemoteFile
|
|||||||
|
|
||||||
public void write(long fileOffset, byte[] data, int off, int len)
|
public void write(long fileOffset, byte[] data, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
requester.doRequest(newRequest(PacketType.WRITE)
|
checkWriteResponse(asyncWrite(fileOffset, data, off, len));
|
||||||
.putUInt64(fileOffset)
|
}
|
||||||
.putUInt32(len - off)
|
|
||||||
.putRawBytes(data, off, len)
|
protected Promise<Response, SFTPException> asyncWrite(long fileOffset, byte[] data, int off, int len)
|
||||||
).ensureStatusPacketIsOK();
|
throws IOException {
|
||||||
|
return requester.request(newRequest(PacketType.WRITE)
|
||||||
|
.putUInt64(fileOffset)
|
||||||
|
.putUInt32(len - off)
|
||||||
|
.putRawBytes(data, off, len)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise)
|
||||||
|
throws SFTPException {
|
||||||
|
responsePromise.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttributes(FileAttributes attrs)
|
public void setAttributes(FileAttributes attrs)
|
||||||
throws IOException {
|
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() {
|
public int getOutgoingPacketOverhead() {
|
||||||
return 1 + // packet type
|
return 1 + // packet type
|
||||||
4 + // request id
|
4 + // request id
|
||||||
4 + // next length
|
4 + // next length
|
||||||
handle.length() + // next
|
handle.length + // next
|
||||||
8 + // file offset
|
8 + // file offset
|
||||||
4 + // data length
|
4 + // data length
|
||||||
4; // packet length
|
4; // packet length
|
||||||
@@ -98,17 +117,25 @@ public class RemoteFile
|
|||||||
public class RemoteFileOutputStream
|
public class RemoteFileOutputStream
|
||||||
extends OutputStream {
|
extends OutputStream {
|
||||||
|
|
||||||
|
|
||||||
private final byte[] b = new byte[1];
|
private final byte[] b = new byte[1];
|
||||||
|
|
||||||
|
private final int maxUnconfirmedWrites;
|
||||||
|
private final Queue<Promise<Response, SFTPException>> unconfirmedWrites;
|
||||||
|
|
||||||
private long fileOffset;
|
private long fileOffset;
|
||||||
|
|
||||||
public RemoteFileOutputStream() {
|
public RemoteFileOutputStream() {
|
||||||
this(0);
|
this(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteFileOutputStream(long fileOffset) {
|
public RemoteFileOutputStream(long startingOffset) {
|
||||||
this.fileOffset = fileOffset;
|
this(startingOffset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteFileOutputStream(long startingOffset, int maxUnconfirmedWrites) {
|
||||||
|
this.fileOffset = startingOffset;
|
||||||
|
this.maxUnconfirmedWrites = maxUnconfirmedWrites;
|
||||||
|
this.unconfirmedWrites = new LinkedList<Promise<Response, SFTPException>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,10 +148,27 @@ public class RemoteFile
|
|||||||
@Override
|
@Override
|
||||||
public void write(byte[] buf, int off, int len)
|
public void write(byte[] buf, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
RemoteFile.this.write(fileOffset, buf, off, len);
|
if (unconfirmedWrites.size() > maxUnconfirmedWrites) {
|
||||||
|
checkWriteResponse(unconfirmedWrites.remove());
|
||||||
|
}
|
||||||
|
unconfirmedWrites.add(RemoteFile.this.asyncWrite(fileOffset, buf, off, len));
|
||||||
fileOffset += len;
|
fileOffset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush()
|
||||||
|
throws IOException {
|
||||||
|
while (!unconfirmedWrites.isEmpty()) {
|
||||||
|
checkWriteResponse(unconfirmedWrites.remove());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
throws IOException {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RemoteFileInputStream
|
public class RemoteFileInputStream
|
||||||
@@ -140,7 +184,7 @@ public class RemoteFile
|
|||||||
this(0);
|
this(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteFileInputStream(int fileOffset) {
|
public RemoteFileInputStream(long fileOffset) {
|
||||||
this.fileOffset = fileOffset;
|
this.fileOffset = fileOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,4 +230,63 @@ public class RemoteFile
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public class ReadAheadRemoteFileInputStream
|
||||||
|
extends InputStream {
|
||||||
|
|
||||||
|
private final byte[] b = new byte[1];
|
||||||
|
|
||||||
|
private final int maxUnconfirmedReads;
|
||||||
|
private final Queue<Promise<Response, SFTPException>> unconfirmedReads;
|
||||||
|
|
||||||
|
private long fileOffset;
|
||||||
|
private boolean eof;
|
||||||
|
|
||||||
|
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads) {
|
||||||
|
this.maxUnconfirmedReads = maxUnconfirmedReads;
|
||||||
|
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
|
||||||
|
this.fileOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads, long fileOffset) {
|
||||||
|
this.maxUnconfirmedReads = maxUnconfirmedReads;
|
||||||
|
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
|
||||||
|
this.fileOffset = fileOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n)
|
||||||
|
throws IOException {
|
||||||
|
throw new IOException("skip is not supported by ReadAheadFileInputStream, use RemoteFileInputStream instead");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read()
|
||||||
|
throws IOException {
|
||||||
|
return read(b, 0, 1) == -1 ? -1 : b[0] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] into, int off, int len)
|
||||||
|
throws IOException {
|
||||||
|
while (!eof && unconfirmedReads.size() <= maxUnconfirmedReads) {
|
||||||
|
// Send read requests as long as there is no EOF and we have not reached the maximum parallelism
|
||||||
|
unconfirmedReads.add(asyncRead(fileOffset, len));
|
||||||
|
fileOffset += len;
|
||||||
|
}
|
||||||
|
if (unconfirmedReads.isEmpty()) {
|
||||||
|
assert eof;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Retrieve first in
|
||||||
|
final Response res = unconfirmedReads.remove().retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
|
final int recvLen = checkReadResponse(res, into, off);
|
||||||
|
if (recvLen == -1) {
|
||||||
|
eof = true;
|
||||||
|
}
|
||||||
|
return recvLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public abstract class RemoteResource
|
public abstract class RemoteResource
|
||||||
implements Closeable {
|
implements Closeable {
|
||||||
@@ -29,9 +30,9 @@ public abstract class RemoteResource
|
|||||||
|
|
||||||
protected final Requester requester;
|
protected final Requester requester;
|
||||||
protected final String path;
|
protected final String path;
|
||||||
protected final String handle;
|
protected final byte[] handle;
|
||||||
|
|
||||||
protected RemoteResource(Requester requester, String path, String handle) {
|
protected RemoteResource(Requester requester, String path, byte[] handle) {
|
||||||
this.requester = requester;
|
this.requester = requester;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
@@ -48,8 +49,10 @@ public abstract class RemoteResource
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
log.info("Closing `{}`", this);
|
log.debug("Closing `{}`", this);
|
||||||
requester.doRequest(newRequest(PacketType.CLOSE)).ensureStatusPacketIsOK();
|
requester.request(newRequest(PacketType.CLOSE))
|
||||||
|
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
|
||||||
|
.ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,20 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Promise;
|
public final class Request
|
||||||
|
|
||||||
public class Request
|
|
||||||
extends SFTPPacket<Request> {
|
extends SFTPPacket<Request> {
|
||||||
|
|
||||||
private final PacketType type;
|
private final PacketType type;
|
||||||
private final long reqID;
|
private final long reqID;
|
||||||
private final Promise<Response, SFTPException> responsePromise;
|
|
||||||
|
|
||||||
public Request(PacketType type, long reqID) {
|
public Request(PacketType type, long reqID) {
|
||||||
super(type);
|
super(type);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.reqID = reqID;
|
this.reqID = reqID;
|
||||||
responsePromise = new Promise<Response, SFTPException>("sftp / " + reqID, SFTPException.chainer);
|
|
||||||
putUInt32(reqID);
|
putUInt32(reqID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,10 +36,6 @@ public class Request
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Promise<Response, SFTPException> getResponsePromise() {
|
|
||||||
return responsePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Request{" + reqID + ";" + type + "}";
|
return "Request{" + reqID + ";" + type + "}";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
|
import net.schmizz.concurrent.Promise;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface Requester {
|
public interface Requester {
|
||||||
@@ -23,7 +25,9 @@ public interface Requester {
|
|||||||
|
|
||||||
Request newRequest(PacketType type);
|
Request newRequest(PacketType type);
|
||||||
|
|
||||||
Response doRequest(Request req)
|
Promise<Response, SFTPException> request(Request req)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
int getTimeoutMs();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
|
||||||
public class Response
|
public final class Response
|
||||||
extends SFTPPacket<Response> {
|
extends SFTPPacket<Response> {
|
||||||
|
|
||||||
public static enum StatusCode {
|
public static enum StatusCode {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -47,7 +47,7 @@ public class SFTPClient
|
|||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SFTPFileTransfer getFileTansfer() {
|
public SFTPFileTransfer getFileTransfer() {
|
||||||
return xfer;
|
return xfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
|
import net.schmizz.concurrent.Promise;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
import net.schmizz.sshj.connection.channel.direct.Session.Subsystem;
|
import net.schmizz.sshj.connection.channel.direct.Session.Subsystem;
|
||||||
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
|
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
|
||||||
@@ -34,12 +35,12 @@ public class SFTPEngine
|
|||||||
implements Requester, Closeable {
|
implements Requester, Closeable {
|
||||||
|
|
||||||
public static final int MAX_SUPPORTED_VERSION = 3;
|
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 */
|
/** Logger */
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
protected volatile int timeout = DEFAULT_TIMEOUT;
|
protected volatile int timeoutMs = DEFAULT_TIMEOUT_MS;
|
||||||
|
|
||||||
protected final PathHelper pathHelper;
|
protected final PathHelper pathHelper;
|
||||||
|
|
||||||
@@ -61,7 +62,13 @@ public class SFTPEngine
|
|||||||
sub = ssh.startSession().startSubsystem("sftp");
|
sub = ssh.startSession().startSubsystem("sftp");
|
||||||
out = sub.getOutputStream();
|
out = sub.getOutputStream();
|
||||||
reader = new PacketReader(this);
|
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()
|
public SFTPEngine init()
|
||||||
@@ -75,7 +82,7 @@ public class SFTPEngine
|
|||||||
throw new SFTPException("Expected INIT packet, received: " + type);
|
throw new SFTPException("Expected INIT packet, received: " + type);
|
||||||
|
|
||||||
operativeVersion = response.readUInt32AsInt();
|
operativeVersion = response.readUInt32AsInt();
|
||||||
log.info("Server version {}", operativeVersion);
|
log.debug("Server version {}", operativeVersion);
|
||||||
if (MAX_SUPPORTED_VERSION < operativeVersion)
|
if (MAX_SUPPORTED_VERSION < operativeVersion)
|
||||||
throw new SFTPException("Server reported incompatible protocol version: " + operativeVersion);
|
throw new SFTPException("Server reported incompatible protocol version: " + operativeVersion);
|
||||||
|
|
||||||
@@ -110,19 +117,24 @@ public class SFTPEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response doRequest(Request req)
|
public Promise<Response, SFTPException> request(Request req)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
reader.expectResponseTo(req);
|
final Promise<Response, SFTPException> promise = reader.expectResponseTo(req.getRequestID());
|
||||||
log.debug("Sending {}", req);
|
log.debug("Sending {}", req);
|
||||||
transmit(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)
|
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final String handle = doRequest(
|
final byte[] handle = doRequest(
|
||||||
newRequest(PacketType.OPEN).putString(path).putUInt32(OpenMode.toMask(modes)).putFileAttributes(fa)
|
newRequest(PacketType.OPEN).putString(path).putUInt32(OpenMode.toMask(modes)).putFileAttributes(fa)
|
||||||
).ensurePacketTypeIs(PacketType.HANDLE).readString();
|
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
||||||
return new RemoteFile(this, path, handle);
|
return new RemoteFile(this, path, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,9 +150,9 @@ public class SFTPEngine
|
|||||||
|
|
||||||
public RemoteDirectory openDir(String path)
|
public RemoteDirectory openDir(String path)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final String handle = doRequest(
|
final byte[] handle = doRequest(
|
||||||
newRequest(PacketType.OPENDIR).putString(path)
|
newRequest(PacketType.OPENDIR).putString(path)
|
||||||
).ensurePacketTypeIs(PacketType.HANDLE).readString();
|
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
||||||
return new RemoteDirectory(this, path, handle);
|
return new RemoteDirectory(this, path, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,18 +233,19 @@ public class SFTPEngine
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeout(int timeout) {
|
public void setTimeoutMs(int timeoutMs) {
|
||||||
this.timeout = timeout;
|
this.timeoutMs = timeoutMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTimeout() {
|
public int getTimeoutMs() {
|
||||||
return timeout;
|
return timeoutMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
sub.close();
|
sub.close();
|
||||||
|
reader.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FileAttributes stat(PacketType pt, String path)
|
protected FileAttributes stat(PacketType pt, String path)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 LocalFileFilter uploadFilter;
|
||||||
private volatile RemoteResourceFilter downloadFilter;
|
private volatile RemoteResourceFilter downloadFilter;
|
||||||
|
private volatile boolean preserveAttributes = true;
|
||||||
|
|
||||||
public SFTPFileTransfer(SFTPEngine engine) {
|
public SFTPFileTransfer(SFTPEngine engine) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getPreserveAttributes() {
|
||||||
|
return preserveAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreserveAttributes(boolean preserveAttributes) {
|
||||||
|
this.preserveAttributes = preserveAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void upload(String source, String dest)
|
public void upload(String source, String dest)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
new Uploader().upload(new FileSystemFile(source), dest);
|
upload(new FileSystemFile(source), dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -58,7 +67,7 @@ public class SFTPFileTransfer
|
|||||||
@Override
|
@Override
|
||||||
public void upload(LocalSourceFile localFile, String remotePath)
|
public void upload(LocalSourceFile localFile, String remotePath)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
new Uploader().upload(localFile, remotePath);
|
new Uploader().upload(getTransferListener(), localFile, remotePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,7 +75,7 @@ public class SFTPFileTransfer
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
final PathComponents pathComponents = engine.getPathHelper().getComponents(source);
|
final PathComponents pathComponents = engine.getPathHelper().getComponents(source);
|
||||||
final FileAttributes attributes = engine.stat(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) {
|
public void setUploadFilter(LocalFileFilter uploadFilter) {
|
||||||
@@ -87,58 +96,61 @@ public class SFTPFileTransfer
|
|||||||
|
|
||||||
private class Downloader {
|
private class Downloader {
|
||||||
|
|
||||||
private final TransferListener listener = getTransferListener();
|
private void download(final TransferListener listener,
|
||||||
|
final RemoteResourceInfo remote,
|
||||||
private void download(final RemoteResourceInfo remote, final LocalDestFile local)
|
final LocalDestFile local)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final LocalDestFile adjustedFile;
|
final LocalDestFile adjustedFile;
|
||||||
switch (remote.getAttributes().getType()) {
|
switch (remote.getAttributes().getType()) {
|
||||||
case DIRECTORY:
|
case DIRECTORY:
|
||||||
listener.startedDir(remote.getName());
|
adjustedFile = downloadDir(listener.directory(remote.getName()), remote, local);
|
||||||
adjustedFile = downloadDir(remote, local);
|
|
||||||
listener.finishedDir();
|
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
log.warn("Server did not supply information about the type of file at `{}` " +
|
log.warn("Server did not supply information about the type of file at `{}` " +
|
||||||
"-- assuming it is a regular file!", remote.getPath());
|
"-- assuming it is a regular file!", remote.getPath());
|
||||||
case REGULAR:
|
case REGULAR:
|
||||||
listener.startedFile(remote.getName(), remote.getAttributes().getSize());
|
adjustedFile = downloadFile(listener.file(remote.getName(), remote.getAttributes().getSize()),
|
||||||
adjustedFile = downloadFile(remote, local);
|
remote, local);
|
||||||
listener.finishedFile();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IOException(remote + " is not a regular file or directory");
|
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 {
|
throws IOException {
|
||||||
final LocalDestFile adjusted = local.getTargetDirectory(remote.getName());
|
final LocalDestFile adjusted = local.getTargetDirectory(remote.getName());
|
||||||
final RemoteDirectory rd = engine.openDir(remote.getPath());
|
final RemoteDirectory rd = engine.openDir(remote.getPath());
|
||||||
try {
|
try {
|
||||||
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
||||||
download(rri, adjusted.getChild(rri.getName()));
|
download(listener, rri, adjusted.getChild(rri.getName()));
|
||||||
} finally {
|
} finally {
|
||||||
rd.close();
|
rd.close();
|
||||||
}
|
}
|
||||||
return adjusted;
|
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 {
|
throws IOException {
|
||||||
final LocalDestFile adjusted = local.getTargetFile(remote.getName());
|
final LocalDestFile adjusted = local.getTargetFile(remote.getName());
|
||||||
final RemoteFile rf = engine.open(remote.getPath());
|
final RemoteFile rf = engine.open(remote.getPath());
|
||||||
try {
|
try {
|
||||||
|
final RemoteFile.ReadAheadRemoteFileInputStream rfis = rf.new ReadAheadRemoteFileInputStream(16);
|
||||||
final OutputStream os = adjusted.getOutputStream();
|
final OutputStream os = adjusted.getOutputStream();
|
||||||
try {
|
try {
|
||||||
new StreamCopier(rf.getInputStream(), os)
|
new StreamCopier(rfis, os)
|
||||||
.bufSize(engine.getSubsystem().getLocalMaxPacketSize())
|
.bufSize(engine.getSubsystem().getLocalMaxPacketSize())
|
||||||
.keepFlushing(false)
|
.keepFlushing(false)
|
||||||
.listener(listener)
|
.listener(listener)
|
||||||
.copy();
|
.copy();
|
||||||
} finally {
|
} finally {
|
||||||
|
rfis.close();
|
||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -161,33 +173,34 @@ public class SFTPFileTransfer
|
|||||||
|
|
||||||
private class Uploader {
|
private class Uploader {
|
||||||
|
|
||||||
private final TransferListener listener = getTransferListener();
|
private void upload(final TransferListener listener,
|
||||||
|
final LocalSourceFile local,
|
||||||
private void upload(LocalSourceFile local, String remote)
|
final String remote)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final String adjustedPath;
|
final String adjustedPath;
|
||||||
if (local.isDirectory()) {
|
if (local.isDirectory()) {
|
||||||
listener.startedDir(local.getName());
|
adjustedPath = uploadDir(listener.directory(local.getName()), local, remote);
|
||||||
adjustedPath = uploadDir(local, remote);
|
|
||||||
listener.finishedDir();
|
|
||||||
} else if (local.isFile()) {
|
} else if (local.isFile()) {
|
||||||
listener.startedFile(local.getName(), local.getLength());
|
adjustedPath = uploadFile(listener.file(local.getName(), local.getLength()), local, remote);
|
||||||
adjustedPath = uploadFile(local, remote);
|
|
||||||
listener.finishedFile();
|
|
||||||
} else
|
} else
|
||||||
throw new IOException(local + " is not a file or directory");
|
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 {
|
throws IOException {
|
||||||
final String adjusted = prepareDir(local, remote);
|
final String adjusted = prepareDir(local, remote);
|
||||||
for (LocalSourceFile f : local.getChildren(getUploadFilter()))
|
for (LocalSourceFile f : local.getChildren(getUploadFilter()))
|
||||||
upload(f, adjusted);
|
upload(listener, f, adjusted);
|
||||||
return 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 {
|
throws IOException {
|
||||||
final String adjusted = prepareFile(local, remote);
|
final String adjusted = prepareFile(local, remote);
|
||||||
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
|
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
|
||||||
@@ -195,14 +208,16 @@ public class SFTPFileTransfer
|
|||||||
OpenMode.TRUNC));
|
OpenMode.TRUNC));
|
||||||
try {
|
try {
|
||||||
final InputStream fis = local.getInputStream();
|
final InputStream fis = local.getInputStream();
|
||||||
|
final RemoteFile.RemoteFileOutputStream rfos = rf.new RemoteFileOutputStream(0, 16);
|
||||||
try {
|
try {
|
||||||
new StreamCopier(fis, rf.getOutputStream())
|
new StreamCopier(fis, rfos)
|
||||||
.bufSize(engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead())
|
.bufSize(engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead())
|
||||||
.keepFlushing(false)
|
.keepFlushing(false)
|
||||||
.listener(listener)
|
.listener(listener)
|
||||||
.copy();
|
.copy();
|
||||||
} finally {
|
} finally {
|
||||||
fis.close();
|
fis.close();
|
||||||
|
rfos.close();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
rf.close();
|
rf.close();
|
||||||
@@ -210,7 +225,7 @@ public class SFTPFileTransfer
|
|||||||
return adjusted;
|
return adjusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String prepareDir(LocalSourceFile local, String remote)
|
private String prepareDir(final LocalSourceFile local, final String remote)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final FileAttributes attrs;
|
final FileAttributes attrs;
|
||||||
try {
|
try {
|
||||||
@@ -236,7 +251,7 @@ public class SFTPFileTransfer
|
|||||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
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 {
|
throws IOException {
|
||||||
final FileAttributes attrs;
|
final FileAttributes attrs;
|
||||||
try {
|
try {
|
||||||
@@ -250,8 +265,7 @@ public class SFTPFileTransfer
|
|||||||
}
|
}
|
||||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
||||||
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
||||||
remote = engine.getPathHelper().adjustForParent(remote, local.getName());
|
return engine.getPathHelper().adjustForParent(remote, local.getName());
|
||||||
return remote;
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
||||||
return remote;
|
return remote;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -31,7 +31,7 @@ public class StatefulSFTPClient
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
super(engine);
|
super(engine);
|
||||||
this.cwd = getSFTPEngine().canonicalize(".");
|
this.cwd = getSFTPEngine().canonicalize(".");
|
||||||
log.info("Start dir = " + cwd);
|
log.debug("Start dir = {}", cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized String cwdify(String path) {
|
private synchronized String cwdify(String path) {
|
||||||
@@ -40,11 +40,12 @@ public class StatefulSFTPClient
|
|||||||
|
|
||||||
public synchronized void cd(String dirname)
|
public synchronized void cd(String dirname)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
cwd = cwdify(dirname);
|
final String targetCwd = cwdify(dirname);
|
||||||
if (statExistence(cwd) == null) {
|
if (statExistence(targetCwd) == null) {
|
||||||
throw new SFTPException(cwd + ": does not exist");
|
throw new SFTPException(targetCwd + ": does not exist");
|
||||||
}
|
}
|
||||||
log.info("CWD = " + cwd);
|
cwd = targetCwd;
|
||||||
|
log.debug("CWD = {}", cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized List<RemoteResourceInfo> ls()
|
public synchronized List<RemoteResourceInfo> ls()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.signature;
|
package net.schmizz.sshj.signature;
|
||||||
|
|
||||||
@@ -81,6 +61,15 @@ public abstract class AbstractSignature
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] sign() {
|
||||||
|
try {
|
||||||
|
return signature.sign();
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected byte[] extractSig(byte[] sig) {
|
protected byte[] extractSig(byte[] sig) {
|
||||||
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0) {
|
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/**
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright 2009 sshj contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.signature;
|
package net.schmizz.sshj.signature;
|
||||||
|
|
||||||
@@ -74,6 +54,13 @@ public interface Signature {
|
|||||||
*/
|
*/
|
||||||
byte[] sign();
|
byte[] sign();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the signature as blog
|
||||||
|
* @param signature the signature to encode
|
||||||
|
* @return Encoded signature
|
||||||
|
*/
|
||||||
|
byte[] encode(byte[] signature);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify against the given signature.
|
* Verify against the given signature.
|
||||||
*
|
*
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user