Compare commits

...

187 Commits

Author SHA1 Message Date
hierynomus
a95fad89a0 Fixed NPE in decrypt by passing in empty char[] 2015-01-20 09:34:12 +01:00
hierynomus
83c5f2f815 Removed java version check from build file as it breaks project import 2015-01-20 09:32:38 +01:00
hierynomus
b17d3fe867 Fixed some warnings 2015-01-20 09:31:49 +01:00
hierynomus
3cefda5bd3 Processed review comments from @demobox. Thx! 2015-01-20 09:31:24 +01:00
hierynomus
18f364a283 Made signing optional 2015-01-19 22:09:41 +01:00
hierynomus
d68032a9b8 Improved test logging 2015-01-19 21:55:41 +01:00
hierynomus
c73ba8bfa7 Merge branch 'gradle' 2015-01-19 21:32:47 +01:00
hierynomus
7bbfd40627 Moved examples to own 'project' 2015-01-19 21:30:34 +01:00
hierynomus
7ae84be548 Fixed build by adding license headers to new files 2015-01-19 11:54:55 +01:00
hierynomus
f2793d1acf Added osgi bundling info 2015-01-19 10:48:53 +01:00
hierynomus
bca5883422 Gradle build files 2015-01-19 10:23:25 +01:00
hierynomus
3e54e2c955 Merge branch 'heartbeat' 2015-01-19 10:06:23 +01:00
hierynomus
a7802ddcde Added keep-alive mechanism that detects disconnects (Fixes #166) 2015-01-19 10:05:03 +01:00
hierynomus
a7872b394b Added braces and log message to HeartBeater 2015-01-16 10:33:25 +01:00
Jeroen van Erp
3ade3977ef Merge pull request #165 from Boris-de/fix_bsize_bug
Fix bsize bug
2015-01-12 09:51:06 +01:00
Jeroen van Erp
efb2c547f9 Merge pull request #164 from Boris-de/mac_unittests
added unit-tests for the "mac"-package
2015-01-12 09:49:56 +01:00
hierynomus
703a0df09d Revert "no biggie if we don't send EOF on ChannelOutputStream.close()"
This reverts commit d95586508d.
2015-01-12 09:18:42 +01:00
Boris Wachtmeister
73de5b7b08 bugfix: BaseMac would not use bsize in certain cases
The implementation of BaseMac would only take the bsize (size of the
hash) into account if the #doFinal(byte[], int) method was called.
Both other #doFinal methods would behave as if bsize==defbsize and
not cut the hash to the right size.
2015-01-11 21:00:16 +01:00
Boris Wachtmeister
665cbf078a added unit-tests for the "mac"-package 2015-01-11 20:56:36 +01:00
hierynomus
b3ea908996 Upgraded BouncyCastle to 1.51 (Fixes #142) 2015-01-09 14:53:24 +01:00
Jeroen van Erp
11da49a4e7 Merge pull request #141 from ziuchkovski/add-proxy-support
Add proxy support for SocketClient/SSHClient
2015-01-09 14:30:13 +01:00
Jeroen van Erp
5b1f9f2a7d Merge pull request #156 from Boris-de/fix_hmac-sha2
fixed block sizes for hmac-sha2-256 and hmac-sha2-512
2015-01-09 14:15:14 +01:00
hierynomus
268de458e3 Changed log levels (Fixes #161) 2015-01-09 13:45:17 +01:00
hierynomus
834f0f22cd Added gitignore 2015-01-09 13:43:38 +01:00
hierynomus
1daf456cbe Added optional OSGi resolution for jzlib (Fixes #162) 2015-01-09 13:37:01 +01:00
Jeroen van Erp
ea11d34ac8 Merge pull request #157 from Donnerbart/master
Fixed unbounded range in pom.xml
2015-01-09 13:28:25 +01:00
Jeroen van Erp
e961dc1b27 Merge pull request #163 from lichtin/master
Update README.adoc
2015-01-09 13:27:45 +01:00
lichtin
25fbff245f Update README.adoc
Fix link to Google group
2015-01-01 20:23:21 +01:00
Donnerbart
333c23e167 Fixed unbounded range in pom.xml:
[INFO] Failed to resolve artifact.

Unable to get dependency information: Unable to read the metadata file for artifact 'net.schmizz:sshj:jar': Invalid JDK version in profile 'doclint-java8-disable': Unbounded range: [1.8, for project net.schmizz:sshj
  net.schmizz:sshj:jar:0.10.1-SNAPSHOT
2014-11-17 13:37:34 +01:00
Boris Wachtmeister
cf32842d0d added hmac-sha2-256 and hmac-sha2-512 to the README 2014-11-16 17:33:19 +01:00
Boris Wachtmeister
70720de71b fixed block sizes for hmac-sha2-256 and hmac-sha2-512
Both MACs have to use larger block/digest sizes than SHA1.
Additionally the KEX must be changed so that it will resize
the keys "E" and "F" to get keys of the right size for those
MACs (according to section 7.2 of rfc4253)
2014-11-11 19:32:41 +01:00
hierynomus
44e1ce1358 Moved readme to asciidoc format 2014-10-27 10:53:43 +01:00
Jeroen van Erp
921f41f9de Update README.rst 2014-10-01 16:24:37 +02:00
hierynomus
34c4be848a removed default signing and staging plugins 2014-10-01 16:18:48 +02:00
hierynomus
d10e303b1a Added travis config 2014-10-01 16:12:27 +02:00
Shikhar Bhushan
46791c87f5 Merge pull request #148 from bluekeyes/bugfix/await-timeout
Use long for Channel#await timeout
2014-09-18 19:20:29 +05:30
Shikhar Bhushan
af0d873e5b Merge pull request #150 from dkocher/master
Change handle to byte[]. Fix interoperability issue with Tectia SSH Serv...
2014-09-18 19:20:13 +05:30
David Kocher
d37b54b1fd Change handle to byte[]. Fix interoperability issue with Tectia SSH Server. Refer to issue #54. 2014-09-10 11:10:42 +02:00
Billy Keyes
c4408ac6dd Use long for Channel#await duration
This matches the underlying method called by AbstractChannel and is the
standard for timeouts with a TimeUnit.
2014-09-02 15:00:51 -07:00
Bob Ziuchkovski
ebbf440304 Add proxy support for SocketClient/SSHClient 2014-08-13 18:58:45 -06:00
Shikhar Bhushan
ef5a54d33f Merge pull request #139 from dkocher/master
Add constructor with file offset.
2014-08-03 22:06:31 +05:30
David Kocher
66514836c8 Add constructor with file offset. 2014-07-29 14:17:51 +02:00
shikhar
e943d80049 onwards to 0.10.1-SNAPSHOT 2014-07-02 11:44:26 +05:30
shikhar
81931f3b7a restore accidently removed assembly plugin for examples jar 2014-07-02 11:42:15 +05:30
shikhar
b8bfc19ecf release plugin mgmt 2014-07-02 11:36:54 +05:30
shikhar
0cb62c6d44 next release will be 0.10.0 2014-07-02 11:17:40 +05:30
shikhar
0ccc57b5af consistent license headers using plugin 2014-07-02 11:13:22 +05:30
shikhar
4806b1d6c7 Read-ahead input stream moved to its own class, as it will not play nice with mark/reset/skip. Use it by defautl for SFTPFileTransfer.
Closes #76 - no longer a significant difference in scp & sftp transfer speed
2014-06-25 12:42:05 +05:30
shikhar
ecc1d06dc2 StreamCopier logging 2014-06-25 12:38:24 +05:30
shikhar
d95586508d no biggie if we don't send EOF on ChannelOutputStream.close() 2014-06-25 11:21:35 +05:30
shikhar
5ee2f0a417 get rid of over-zealous sending of channel EOF & close messages which was implemented with questionable synchronization
fixes #105

also relevant to #126 since AbstractChannel does not synchronize on
'this' anymore
2014-06-24 17:57:23 +05:30
shikhar
2a7278d239 some small tweaks to PKCS8KeyFile in relation to the PEMReader -> PEMParser transition 2014-06-24 14:21:40 +05:30
shikhar
0875417dde don't close underlying RemoteFile when closing streams of that file - reverts f34667521d 2014-06-24 14:20:04 +05:30
shikhar
0a3ad4f68f not handed over yet 2014-06-24 11:54:06 +05:30
shikhar
fe58ecdee5 Change CONTRIBUTORS to contain the relevant command for getting at this info 2014-06-22 17:25:01 +05:30
shikhar
264e10b40c support multiline password prompts #132 2014-06-22 17:21:54 +05:30
Shikhar Bhushan
a00015969b Merge pull request #136 from dkocher/master
HMAC-SHA2, PuTTY key format, concurrent read for downloads and bug fixes
2014-06-22 17:09:06 +05:30
David Kocher
d6c22fef55 ADd clirr-maven-plugin 2014-06-18 10:16:22 +02:00
David Kocher
9886facf42 Fix test. 2014-06-18 10:08:07 +02:00
David Kocher
01be48508d Throw SSHException for packet length exceeding max size. 2014-06-03 11:55:44 +02:00
David Kocher
bdc541c959 Format client identification. 2014-06-03 11:54:38 +02:00
David Kocher
f2ebbe288f Ignore socket timeout in read which occurs if we have set the timeout to > 0. We should continue reading from the stream unless the reader is interrupted. Note that with the default timeout set to 0, the reader thread will never return. 2014-05-16 22:21:00 +02:00
David Kocher
9297338195 Use plain server message. 2014-05-16 15:33:24 +02:00
David Kocher
a8d2ea2028 Add disconnect message from server. 2014-05-16 15:30:04 +02:00
David Kocher
f34667521d Close remote handles when closing stream. 2014-05-14 23:31:07 +02:00
David Kocher
77f5d7fdb8 Extract encode method for signature. Implement signing for ECDSA. 2014-05-14 12:33:46 +02:00
David Kocher
08d0e59b6b Logging 2014-05-14 11:06:33 +02:00
David Kocher
5c540b6889 Interrupt packet reader thread on close. 2014-05-14 11:03:46 +02:00
David Kocher
baa8c8e995 Merge branch 'master' of https://github.com/xardazz/sshj 2014-05-09 14:04:25 +02:00
David Kocher
f354fd6661 Implement read ahead to speed up transfer rates for downloads by a magnitude. 2014-05-09 13:43:52 +02:00
David Kocher
93f1543af8 Add PuTTY key file implementation. 2014-05-09 10:37:53 +02:00
David Kocher
63424657da Check index length. 2014-05-08 16:17:43 +02:00
David Kocher
131e85c4d0 Add write method to append single entry. 2014-05-07 17:02:18 +02:00
David Kocher
587684c6a8 Fix null pointer. 2014-05-07 17:01:45 +02:00
xardazz
66f67db21b Update KeyType.java
remove my common lib
2014-05-07 13:14:16 +04:00
David Kocher
3356f533d0 Add dependencyManagement. 2014-05-07 10:42:27 +02:00
David Kocher
97535bbcae Merge interfaces. 2014-05-07 10:37:14 +02:00
David Kocher
896b0ea288 Add provider with reader resource. 2014-05-06 21:22:12 +02:00
David Kocher
60d54fa5de Addendum 2014-05-06 21:21:23 +02:00
David Kocher
06e421e752 Extract formats. Add PuTTY to enum. 2014-05-06 15:41:35 +02:00
Alexey Gromov
b5796f5e74 fix version 2014-05-06 12:13:11 +04:00
Alexey Gromov
0f7355a277 add ecdsa 2014-05-06 12:09:50 +04:00
David Kocher
466ff99e1c Update BC dependency to 1.50. 2014-05-05 13:12:48 +02:00
David Kocher
1f992c3fae Ignore user auth banner in transport. 2014-05-05 13:12:10 +02:00
David Kocher
df6019accc Fix type of fileOffset to long. 2014-05-05 13:11:54 +02:00
David Kocher
fdb891b842 Add hmac-sha2-256 and hmac-sha2-512. 2014-05-05 13:11:27 +02:00
Shikhar Bhushan
5159a799df fix the fix for #90 - need to statExistence of targetCwd not cwd 2013-09-07 11:39:28 -04:00
shikhar
78e5a2e30e bump ident for 0.9.1 before i forget 2013-08-11 22:35:19 -04:00
shikhar
db22f08f97 [maven-release-plugin] prepare for next development iteration 2013-08-11 22:25:50 -04:00
shikhar
c8cfc796af [maven-release-plugin] prepare release v0.9.0 2013-08-11 22:25:46 -04:00
shikhar
d9c0c6725c for 0.9.0 2013-08-11 22:08:26 -04:00
shikhar
b2297c6b44 version bumps 2013-08-11 18:56:46 -04:00
shikhar
e10ad28f2f inherit from sonatype oss parent pom 2013-08-11 18:56:46 -04:00
shikhar
61fc00a90a fix javadoc warning 2013-08-11 18:56:46 -04:00
shikhar
c8ef7ff0ca 0.9.0 snapshot 2013-08-11 17:27:04 -04:00
shikhar
e6c4f6ae69 #90 - only update cwd state if stat succeeds 2013-08-11 17:16:40 -04:00
shikhar
3418df7a56 #114 - visibility issue 2013-08-11 16:04:49 -04:00
shikhar
0ddd1f38c5 Simplify the UserAuth.authenticate(..) interface, move the multi-auth-method trial-and-error into SSHClient API 2013-04-15 22:56:24 -04:00
shikhar
0ec6918d7a minor javadoc 2013-03-24 19:09:21 -04:00
shikhar
88a88c5dba change transport layer to use millisecond timeouts 2013-03-24 17:36:11 -04:00
shikhar
6656214803 change connection layer to use millisecond timeouts 2013-03-24 17:27:36 -04:00
shikhar
c781724028 whitespace 2013-03-24 14:55:09 -04:00
shikhar
eefaa26882 missing flush() during banner exchange 2013-03-24 14:54:38 -04:00
Shikhar Bhushan
0d52441f01 Add 'unconfirmed writes' feature to SFTP RemoteFileOutputStream, allowing for major speedups
Thanks to @romainreuillon for the idea and initial implementation! #97
2013-02-23 18:16:29 -05:00
Shikhar Bhushan
9539ff6b7a In SFTPEngine / Requester, move from using TimeUnit.SECONDS to TimeUnit.MILLISECONDS, and start using some more explicit naming 2013-02-23 16:26:37 -05:00
Shikhar Bhushan
1ced1d4fdc Get rid of Requester.doRequest(), replace with request() method that returns the response promise. Make getTimeout() part of the interface. 2013-02-23 16:22:28 -05:00
Shikhar Bhushan
77924fd0be Revert "Implement concurent write requests."
This reverts commit 9acff6202c.
2013-02-23 16:00:53 -05:00
Shikhar Bhushan
3f195649fa Merge pull request #98 from andreaturli/master
Updated bouncycastle dependency
2013-02-23 03:41:44 -08:00
Shikhar Bhushan
42a4358f5c Merge pull request #104 from mpoindexter/master
ArrayIndexOutOfBounds when writing to a SFTP RemoteFile's OutputStream with large buffer
2013-02-23 03:41:19 -08:00
mpoindexter
61ce0f4868 Fix ArrayIndexOutOfBounds when writing big buffer
If ChannelOutputStream.write(byte[], int, int) was called with a buffer larger 
than bufferSize the loop in that method would call DataBuffer.write with a small len
and a large off.  This would cause the calculation in line 90 to return a negative n
leading to a ArrayIndexOutOfBounds.  The offset should not be taken into account when
calculating the number of bytes to put in the buffer.
2013-02-21 21:05:20 -08:00
Shikhar Bhushan
777995af3b Merge pull request #97 from romainreuillon/master
Make write a lot faster
2013-01-06 12:30:14 -08:00
Andrea Turli
635cf88acd updatet bouncycastle dep to the latest version 2012-12-31 01:44:10 +01:00
Romain Reuillon
ce515fddcd Change the scope back to protected, the change was unwanted. 2012-12-12 08:33:32 +01:00
Romain Reuillon
9acff6202c Implement concurent write requests. 2012-12-12 08:29:26 +01:00
Shikhar Bhushan
cbd118e0b1 fix #84 - debug log good enough 2012-10-21 02:13:55 +05:30
Shikhar Bhushan
a8cf749d95 #87 - include full exception trace when logging transport death 2012-10-21 01:45:13 +05:30
Shikhar Bhushan
f3d4707ef0 fix #89 - use IllegalStateException from SSHClient when sanity-check assertions fail 2012-10-21 01:40:07 +05:30
Shikhar Bhushan
4c5da634ad don't do a looped cond.await(timeout, unit) as that handles spurious wakeups, and it'll be buggy if the wakeup is due to a call to clear() 2012-10-21 01:21:36 +05:30
Shikhar Bhushan
2fdafb76fd [maven-release-plugin] prepare for next development iteration 2012-07-08 09:55:32 -04:00
Shikhar Bhushan
80b164a299 [maven-release-plugin] prepare release v0.8.1 2012-07-08 09:55:22 -04:00
Shikhar Bhushan
75418f33b7 Next release to be 0.8.1 2012-07-08 09:50:43 -04:00
Shikhar Bhushan
732de2b605 make logs less chatty
#80
2012-07-05 00:10:40 +05:30
Shikhar Bhushan
4fb56b868f Per #77 use regex matching inside PasswordResponseProvider. Also remove the 'gaveAlready' state, we can leave such logic to the PasswordFinder to implement if needed. 2012-06-06 23:59:41 +01:00
Shikhar Bhushan
a877ec1448 AbstractChannel#close() should be no-op if already closed. Fixes #53. 2012-06-06 22:57:27 +01:00
Shikhar Bhushan
b44631ea97 Better naming for some AbstractChannel's lock/event members 2012-06-06 22:51:25 +01:00
Shikhar Bhushan
a50962ba2f Small cleanup 2012-05-19 11:18:30 +01:00
Shikhar Bhushan
e8215e4af2 Update NOTICE 2012-05-14 11:33:05 +02:00
Shikhar Bhushan
3c2bda3196 docfix - not part of the contract 2012-05-12 22:13:22 +01:00
Shikhar Bhushan
b13e22084b [maven-release-plugin] prepare for next development iteration 2012-05-12 21:48:45 +01:00
Shikhar Bhushan
e7ba0e1e26 [maven-release-plugin] prepare release v0.8.0 2012-05-12 21:48:39 +01:00
Shikhar Bhushan
f712720538 Update CONTRIBUTORS 2012-05-12 17:33:07 +02:00
Shikhar Bhushan
540708e540 Provide a preference SFTPFileTransfer.setPreserveAttributes() to not set file attributes post upload or download.
Should address issue #42 / pull request #43
2012-05-12 16:24:01 +01:00
Shikhar Bhushan
e4d3a1f866 Some documentation on the FileTransfer interface. 2012-05-12 16:03:57 +01:00
Shikhar Bhushan
33969340e2 small tweak 2012-05-12 14:37:07 +01:00
Shikhar Bhushan
d65df3c9bc - Move trailing slash removal from SFTPEngine.mkdirs() to PathHelper.getComponents()
- Try to make the PathHelper.getComponents() code clearer
- Added some tests for PathHelper.getComponents()
2012-05-12 14:28:28 +01:00
Shikhar Bhushan
d2b9248535 Decouple PathHelper and SFTPEngine, introduce Canonicalizer interface 2012-05-12 11:23:44 +01:00
Shikhar Bhushan
431be8e7c7 Lower the ceiling on max remote packet size (so we don't allocate huge buffers) & spell it out mor explicitly 2012-05-12 11:09:41 +01:00
Shikhar Bhushan
885c602ab8 Merge pull request #66 from UrsKR/trailingseparator
SFTP client no longer tries to create folders twice when path has trailing separator
2012-05-12 03:09:04 -07:00
Shikhar Bhushan
8262e8fc98 Update CONTRIBUTORS 2012-04-28 13:21:47 +02:00
Shikhar Bhushan
844c5d7f77 Merge pull request #73 from aledsage/Issue-72-Buffer-Too-Large
Issue 72: fix for infinite loop if allocate too large a buffer
2012-04-28 04:16:16 -07:00
Aled Sage
fb690c4fb0 Issue 72: fix for infinite loop if allocate too large a buffer (due to invalid packet size) 2012-04-26 11:43:29 +01:00
Shikhar Bhushan
ab04596a20 Merge pull request #69 from ludoza/patch-1
fixed simple example.
2012-04-15 03:00:18 -07:00
ludoza
9ffdc35f93 fixed simple example. 2012-04-11 18:02:40 +03:00
Shikhar Bhushan
93e23f4cfb Don't try to send a disconnect packet if never connected. Fixes GH-67. 2012-04-05 12:30:56 -04:00
Shikhar Bhushan
504637099d copyright 2012-04-05 12:30:55 -04:00
Shikhar Bhushan
cafd9217bf whitespace 2012-04-05 12:30:55 -04:00
Urs Reupke
c627fabebd MkDirs no longer tries to create folders twice when path has trailing slash. 2012-03-23 10:58:42 +01:00
Shikhar Bhushan
1c4781a65d Merge pull request #65 from ryantenney/logging-fix
Avoid string concatenation in log statements
2012-03-20 01:10:52 -07:00
Ryan Tenney
aac7af2827 Avoid string concatenation in log statements. 2012-03-19 13:34:38 -04:00
Shikhar Bhushan
11c286b9b9 . 2012-02-08 20:01:58 +00:00
Shikhar Bhushan
7fae513fd8 google group 2012-02-08 20:01:39 +00:00
Shikhar Bhushan
53ad9d2288 int->long 2012-02-06 23:36:18 +00:00
Shikhar Bhushan
ee07072846 Make window size a long, as it can be upto (2^32 - 1)
Fix for #57
2012-02-06 22:24:52 +00:00
Shikhar Bhushan
d38bbbcdf7 clearer... 2012-02-05 19:54:42 +00:00
Shikhar Bhushan
bc59c81dbc Refactor TransferListener interface to support thread-safe, immutable implementation.
Fix #56
2012-01-29 22:54:17 +00:00
Shikhar Bhushan
d70d37cf4e Version string update 2012-01-29 22:52:59 +00:00
Shikhar Bhushan
777d82912c Merge pull request #55 from hierynomus/default-tty
Set default tty to vt100, as specified in the javadoc
2012-01-26 13:52:39 -08:00
hierynomus
f5db3e1563 Set default tty to vt100, as specified in the javadoc 2012-01-19 10:19:19 +01:00
Shikhar Bhushan
7e524f5c6f Make disconnect() an operation that can be repeated without side-effects beyond the first call. 2012-01-08 10:20:46 +00:00
Shikhar Bhushan
dbb3f62e82 [maven-release-plugin] prepare for next development iteration 2012-01-08 09:32:47 +00:00
Shikhar Bhushan
16a363fef6 [maven-release-plugin] prepare release v0.7.0 2012-01-08 09:32:41 +00:00
Shikhar Bhushan
9b0d39a798 Remove the SFTPClient.getFileTansfer() method that has typo altogether as this is a simple change to make for clients. 2012-01-08 09:30:05 +00:00
Shikhar Bhushan
81e36153d7 wrapping 2012-01-08 09:10:07 +00:00
Shikhar Bhushan
3026be282a Refactored the local port forwarding API; give caller control over initializing and cleaning up the server socket used.
Also removed 'server socket factory' stuff from SocketClient.
2012-01-05 22:26:44 +00:00
Shikhar Bhushan
8eedeb25fa Merge pull request #50 from iocanel/master
Remove bouncycastle version range from OSGi metadata.
2012-01-02 06:52:50 -08:00
Ioannis Canellos
de11880648 Removed package version from bouncycastle imports 2012-01-02 15:04:12 +02:00
Shikhar Bhushan
1ff4772f3f update id string 2011-12-20 11:12:35 +00:00
Shikhar Bhushan
22a5ffe735 fix for #47 - should send data down rather than sitting around waiting for an adjustment if there is window space available 2011-12-20 10:41:49 +00:00
Shikhar Bhushan
7a77f85ced docfix 2011-12-20 10:37:32 +00:00
Shikhar Bhushan
0002fe8b40 Made some Buffer subclasses final 2011-12-19 22:52:41 +00:00
Shikhar Bhushan
3028e7f218 Fix logging of window adjustments 2011-12-19 21:56:44 +00:00
Shikhar Bhushan
333e1cb7b8 small cleanup 2011-12-04 19:10:34 +00:00
Shikhar Bhushan
945d430916 Removed deprecated Session.Command's methods - getOutputAsString() and getErrorAsString() 2011-12-04 18:26:05 +00:00
Shikhar Bhushan
73b903784a Next version will be 0.7.0 2011-12-04 18:24:00 +00:00
Shikhar Bhushan
7d53649a85 . 2011-12-04 18:23:15 +00:00
Shikhar Bhushan
e193db9a14 Fix example in SSHClient doc 2011-12-04 18:14:27 +00:00
Shikhar Bhushan
a942edb911 Add SFTPClient.getFileTransfer() and deprecate getFileTansfer() which has typo 2011-12-04 18:11:30 +00:00
Shikhar Bhushan
137a7f5956 (reformat) 2011-12-04 17:48:42 +00:00
Shikhar Bhushan
718ff503df Merge pull request #41 from hierynomus/known-hosts
OpenSSH Known hosts format re-implemented
2011-12-04 09:35:58 -08:00
Shikhar Bhushan
d933b2538e Upgrade maven-bundle-plugin to 2.3.6 to fix #37 [https://issues.apache.org/jira/browse/FELIX-3058] 2011-12-04 17:10:33 +00:00
Shikhar Bhushan
ea6f9ceed2 Correct version 2011-12-04 13:54:19 +00:00
rws
07c61b14e8 Change SocketClient to public so that SSHClient can be mocked for testing. 2011-12-04 21:51:58 +08:00
hierynomus
4b175e6938 Re-implemented OpenSSHKnownHostsVerifier to deal with the real format 2011-11-10 09:51:18 +01:00
Shikhar Bhushan
f7e47cffa0 [maven-release-plugin] prepare for next development iteration 2011-10-02 22:17:46 +01:00
Shikhar Bhushan
42dddc7f7e [maven-release-plugin] prepare release v0.6.1 2011-10-02 22:17:36 +01:00
Shikhar Bhushan
f1b3dbb102 Restore mutual exclusion of sendChannelRequest() and gotResponse() in AbstractChannel (but rather than make methods synchronized do it on the queue, which itself doesn't need to be thread-safe). Regression due to 1a2351c5ee. Fixes #35. 2011-10-02 09:47:49 +01:00
Shikhar Bhushan
f83bf2cd3f [maven-release-plugin] prepare for next development iteration 2011-09-26 12:41:23 +01:00
227 changed files with 4776 additions and 3166 deletions

17
.gitignore vendored Normal file
View 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
View File

@@ -0,0 +1 @@
language: java

View File

@@ -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
View File

@@ -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
View 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!

View File

@@ -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
View 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
View 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
View 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>

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

252
pom.xml
View File

@@ -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> <dependencies>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>bcprov-jdk15on</artifactId>
<version>1.6.1</version> <version>1.51</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> <version>1.51</version>
<scope>provided</scope> </dependency>
</dependency> <dependency>
<dependency> <groupId>com.jcraft</groupId>
<groupId>junit</groupId> <artifactId>jzlib</artifactId>
<artifactId>junit</artifactId> <version>1.1.3</version>
<version>4.8.2</version> </dependency>
<scope>test</scope> <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>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</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>

View File

@@ -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
View 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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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();

View 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));
}
}

View 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;
}

View 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);
}

View 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();
}
}
}

View File

@@ -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;
}
} }

View File

@@ -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.

View File

@@ -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);
} }

View File

@@ -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;
}
} }

View File

@@ -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() {

View File

@@ -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(&quot;hostname&quot;); * client.connect(&quot;hostname&quot;);
* try { * try {
* client.authPassword(&quot;username&quot;, &quot;password&quot;); * client.authPassword(&quot;username&quot;, &quot;password&quot;);
@@ -103,6 +104,7 @@ import java.util.List;
* cmd.join(1, TimeUnit.SECONDS); * cmd.join(1, TimeUnit.SECONDS);
* } finally { * } finally {
* session.close(); * session.close();
* }
* } finally { * } finally {
* client.disconnect(); * client.disconnect();
* } * }
@@ -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,12 +354,13 @@ 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");
}
}
} }

View File

@@ -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.

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");

View File

@@ -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();
} }

View File

@@ -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.

View File

@@ -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;
}
} }

View File

@@ -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 {
if (isOpen()) {
try { try {
sendClose(); sendClose();
} catch (TransportException e) { } catch (TransportException e) {
if (!close.inError()) if (!closeEvent.inError())
throw e; throw e;
} }
close.await(conn.getTimeout(), TimeUnit.SECONDS); closeEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
} 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,7 +350,8 @@ 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);
synchronized (chanReqResponseEvents) {
trans.write( trans.write(
newBuffer(Message.CHANNEL_REQUEST) newBuffer(Message.CHANNEL_REQUEST)
.putString(reqType) .putString(reqType)
@@ -383,9 +367,11 @@ public abstract class AbstractChannel
} }
return responseEvent; return responseEvent;
} }
}
private void gotResponse(boolean success) private void gotResponse(boolean success)
throws ConnectionException { throws ConnectionException {
synchronized (chanReqResponseEvents) {
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll(); final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
if (responseEvent != null) { if (responseEvent != null) {
if (success) if (success)
@@ -396,14 +382,12 @@ public abstract class AbstractChannel
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR, throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
"Received response to channel request when none was requested"); "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="

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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();
}
}
public synchronized void setClosed() {
closed = true; 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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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() {
synchronized (lock) {
return size; 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;
} }
} }

View File

@@ -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);
} }

View File

@@ -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!");
} }
} }

View File

@@ -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.

View File

@@ -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. */

View File

@@ -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();
}
} }

View File

@@ -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.

View File

@@ -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. */

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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.

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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());

View File

@@ -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);

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;
} }
} }

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}
} }

View File

@@ -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.

View File

@@ -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:

View File

@@ -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,30 +15,28 @@
*/ */
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))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
.ensurePacketTypeIs(PacketType.ATTRS) .ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes(); .readFileAttributes();
} }
@@ -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));
}
protected Promise<Response, SFTPException> asyncWrite(long fileOffset, byte[] data, int off, int len)
throws IOException {
return requester.request(newRequest(PacketType.WRITE)
.putUInt64(fileOffset) .putUInt64(fileOffset)
.putUInt32(len - off) .putUInt32(len - off)
.putRawBytes(data, off, len) .putRawBytes(data, off, len)
).ensureStatusPacketIsOK(); );
}
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;
}
}
} }

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 + "}";

View File

@@ -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();
} }

View File

@@ -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 {

View File

@@ -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;
} }

View File

@@ -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)

View File

@@ -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.

View File

@@ -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");
} }
if (getPreserveAttributes())
copyAttributes(remote, adjustedFile); 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");
if (getPreserveAttributes())
engine.setAttributes(adjustedPath, getAttributes(local)); 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;

View File

@@ -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.

View File

@@ -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()

View File

@@ -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;

View File

@@ -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