Compare commits

..

209 Commits

Author SHA1 Message Date
Jeroen van Erp
a18d623f44 Release notes for 0.12.0 2015-04-14 13:14:15 +02:00
Jeroen van Erp
6855873ffd removed release plugin 2015-04-14 12:57:40 +02:00
Jeroen van Erp
2ca8d8b19e Upgraded gradle 2015-04-14 12:03:38 +02:00
Jeroen van Erp
da32b145df Added braces to single-line statements 2015-04-13 11:50:34 +02:00
Jeroen van Erp
8ea6bb4a66 Updated README for fixed #181 and #180 issue 2015-04-01 11:28:14 +02:00
Jeroen van Erp
6cf767528a Added comment to check why that field is needed 2015-04-01 11:25:43 +02:00
Jeroen van Erp
b123a6ae30 Merge pull request #181 from iterate-ch/issue-180
Fix length field for SSH_FXP_WRITE packets.
2015-04-01 11:24:30 +02:00
Jeroen van Erp
4250c61e45 Deprecated Proxy connect methods, moved Sockets utility class to backport package 2015-03-31 09:27:13 +02:00
Jeroen van Erp
ace09fa8c8 Added support for HTTP CONNECT proxies by implementing custom Socket (Fixes #170) 2015-03-30 21:53:04 +02:00
Jeroen van Erp
8398b6e3c3 Revert "Added support for (unauthenticated) HTTP proxies (fixes #170)"
This reverts commit fc535a5e76.
2015-03-30 21:48:07 +02:00
Jeroen van Erp
3c1e0c1629 Updated readme 2015-03-27 16:04:42 +01:00
Andrew Kondratovich
e6c7c17664 Correctly closing channel and socket when LocalPortForwarder fails to open it. (Fix #175) 2015-03-27 16:02:07 +01:00
Jeroen van Erp
1e061aef25 Updated readme with work in progress for next release 2015-03-27 15:30:58 +01:00
Jeroen van Erp
66b772bac1 Compiling for JDK6, fixes #179 and #185 2015-03-27 15:25:45 +01:00
Jeroen van Erp
fc535a5e76 Added support for (unauthenticated) HTTP proxies (fixes #170) 2015-03-27 15:19:04 +01:00
Jeroen van Erp
c7373f05cc Merge pull request #186 from bluekeyes/fix/read-end-of-stream
Detect end-of-stream in TransportImpl#init
2015-03-16 10:34:47 +01:00
Billy Keyes
3ebd2eb363 Detect end-of-stream in TransportImpl#init
OpenSSH will drop connections based on the value of MaxStartups when
there are too many unauthenticated connection. When this happens, reads
on the client socket return -1, which was previously inserted into the
identification buffer, leading to the error in #118.
2015-03-13 15:34:18 -07:00
David Kocher
8638091517 Fix length field for SSH_FXP_WRITE packets. 2015-02-24 15:27:08 +01:00
hierynomus
5fc08a3fc8 back to snapshot 2015-01-23 10:08:51 +01:00
hierynomus
92df7c6924 v0.11.0 2015-01-23 10:07:43 +01:00
hierynomus
8c0967ca93 Preparing for 0.11.0 release 2015-01-22 12:40:53 +01:00
hierynomus
cb5b7f0943 Setting up integration testing 2015-01-22 09:47:11 +01:00
hierynomus
de2ede05e7 Added gradle wrapper 2015-01-21 10:27:26 +01:00
hierynomus
4a90f99c5f Not sending EOF on OutputStream close (reopens #143) 2015-01-21 10:25:28 +01:00
hierynomus
e348f698e6 test logging 2015-01-20 19:05:15 +01:00
hierynomus
d59efaa5f9 Fixed KeepAliveRunner for when service not yet set 2015-01-20 17:13:47 +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
237 changed files with 5353 additions and 3193 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.bat text eol=crlf

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>
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>
git log --format='%aN <%aE>' | awk '{arr[$0]++} END{for (i in arr){print arr[i], i;}}' | sort -rn | cut -d\ -f2-

2
NOTICE
View File

@@ -1,5 +1,5 @@
sshj - SSHv2 library for Java
Copyright 2010-2011 sshj contributors
Copyright 2010-2012 sshj contributors
This product includes code derived from software developed at
The Apache Software Foundation (http://www.apache.org/):

112
README.adoc Normal file
View File

@@ -0,0 +1,112 @@
= sshj - SSHv2 library for Java
Jeroen van Erp
:sshj_groupid: com.hierynomus
:sshj_version: 0.11.0
:source-highlighter: pygments
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 :)
== Getting SSHJ
To get SSHJ, you have two options:
. Add a dependency to SSHJ to your project.
. Build SSHJ yourself.
And, if you want, you can also run the SSHJ examples.
Binary releases of SSHJ are not provided here, but you can download it http://search.maven.org/#artifactdetails%7C{sshj_groupid}%7Csshj%7C{sshj_version}%7Cjar[straight from the Maven Central repository] if you want to.
== Depending on SSHJ
If you're building your project using Maven, you can add the following dependency to the `pom.xml`:
[source,xml,subs="verbatim,attributes"]
----
<dependency>
<groupId>{sshj_groupid}</groupId>
<artifactId>sshj</artifactId>
<version>{sshj_version}</version>
</dependency>
----
If your project is built using another build tool that uses the Maven Central repository, translate this dependency into the format used by your build tool.
== Building SSHJ
. Clone the Overthere repository.
. Ensure you have Java6 installed with the http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html[Unlimited strength Java Cryptography Extensions (JCE)].
. Run the command `./gradlew clean build`.
== Running the examples
In the `examples` directory, there is a separate Maven project that shows how the library can be used in some sample cases. If you want to run them, follow these guidelines:
. Install http://maven.apache.org/[Maven 2.2.1] or up.
. Clone the Overthere repository.
. Go into the `examples` directory and run the command `mvn eclipse:eclipse`.
. Import the `examples` project into Eclipse.
. Change the login details in the example classes (address, username and password) and run them!
== 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!
== Release history
SSHJ 0.12.0 (2015-04-14)::
* Added support for HTTP proxies when running JDK6 or JDK7, fixes: https://github.com/hierynomus/sshj/issues/170[#170]
* Merged https://github.com/hierynomus/sshj/issues/186[#186]: Fix for detecting end-of-stream
* Compiling to JDK6, fixes https://github.com/hierynomus/sshj/issues/179[#179] and https://github.com/hierynomus/sshj/issues/185[#185]
* Correctly close socket and channel when LocalPortForwarder fails to open and start the channel (Fixes https://github.com/hierynomus/sshj/issues/175[#175] and https://github.com/hierynomus/sshj/issues/176[#176])
* Merged https://github.com/hierynomus/sshj/issues/181[#181]: Invalid write packet length when reading with offset (Fixes https://github.com/hierynomus/sshj/issues/180[#180])
SSHJ 0.11.0 (2015-01-23)::
* New maven coordinates `com.hierynomus:sshj:0.11.0` as https://github.com/hierynomus[@hierynomus] took over as maintainer of SSHJ
* Migrated build system to Gradle 2.2.1
* Merged https://github.com/hierynomus/sshj/issues/150[#150]: Fix for incorrect file handle on some SSH servers, fixes: https://github.com/hierynomus/sshj/issues/54[#54], https://github.com/hierynomus/sshj/issues/119[#119], https://github.com/hierynomus/sshj/issues/168[#168], https://github.com/hierynomus/sshj/issues/169[#169]
* Made `jzlib` optional in OSGi bundling, fixes: https://github.com/hierynomus/sshj/issues/162[#162]
* Improved some log levels, fixes: https://github.com/hierynomus/sshj/issues/161[#161]
* Merged https://github.com/hierynomus/sshj/issues/156[#156], https://github.com/hierynomus/sshj/issues/164[#164], https://github.com/hierynomus/sshj/issues/165[#165]: Fixed block sizes for `hmac-sha2-256` and `hmac-sha2-512`
* Merged https://github.com/hierynomus/sshj/issues/141[#141]: Add proxy support
* Merged https://github.com/hierynomus/sshj/issues/157[#157], https://github.com/hierynomus/sshj/issues/163[#163]: Doc and build fixes
* Upgraded BouncyCastle to 1.51, fixes: https://github.com/hierynomus/sshj/issues/142[#142]
* Implemented keep-alive with connection drop detection, fixes https://github.com/hierynomus/sshj/issues/166[#166]

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
}

161
build.gradle Normal file
View File

@@ -0,0 +1,161 @@
apply plugin: "java"
apply plugin: "maven"
apply plugin: "signing"
apply plugin: "osgi"
group = "com.hierynomus"
version = "0.12.0"
repositories {
mavenCentral()
mavenLocal()
}
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
compile {
transitive = false
}
}
test {
include "**/*Test.*"
afterSuite { descriptor, result ->
if (descriptor.className != null) {
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;

View File

@@ -0,0 +1,55 @@
/**
* 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.examples;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** This examples demonstrates how to setup keep-alive to detect connection dropping. */
public class KeepAlive {
public static void main(String... args)
throws IOException, InterruptedException {
DefaultConfig defaultConfig = new DefaultConfig();
defaultConfig.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE);
final SSHClient ssh = new SSHClient(defaultConfig);
try {
ssh.addHostKeyVerifier(new PromiscuousVerifier());
ssh.connect(args[0]);
ssh.getConnection().getKeepAlive().setKeepAliveInterval(5); //every 60sec
ssh.authPassword(args[1], args[2]);
Session session = ssh.startSession();
session.allocateDefaultPTY();
new CountDownLatch(1).await();
try {
session.allocateDefaultPTY();
} finally {
session.close();
}
} finally {
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
/**
* This example demonstrates local port forwarding, i.e. when we listen on a particular address and port; and forward
@@ -41,8 +43,16 @@ public class LocalPF {
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
* google.com:80
*/
ssh.newLocalPortForwarder(new InetSocketAddress("localhost", 8080), "google.com", 80)
.listen();
final LocalPortForwarder.Parameters params
= new LocalPortForwarder.Parameters("0.0.0.0", 8080, "google.com", 80);
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(params.getLocalHost(), params.getLocalPort()));
try {
ssh.newLocalPortForwarder(params, ss).listen();
} finally {
ss.close();
}
} finally {
ssh.disconnect();

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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
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");
* 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
* limitations under the License.
*/
package examples;
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.StreamCopier;

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Wed Jan 21 09:17:25 CET 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip

164
gradlew vendored Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

254
pom.xml
View File

@@ -1,28 +1,46 @@
<?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>
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>bundle</packaging>
<version>0.6.1</version>
<version>0.10.1-SNAPSHOT</version>
<name>sshj</name>
<description>SSHv2 library for Java</description>
<url>http://github.com/shikhar/sshj</url>
<url>http://github.com/hierynomus/sshj</url>
<inceptionYear>2009</inceptionYear>
<issueManagement>
<system>github</system>
<url>http://github.com/shikhar/sshj/issues</url>
<url>http://github.com/hierynomus/sshj/issues</url>
</issueManagement>
<scm>
<connection>scm:git:git://github.com/shikhar/sshj.git</connection>
<developerConnection>scm:git:git@github.com:shikhar/sshj.git</developerConnection>
<url>http://github.com/shikhar/sshj</url>
<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>
@@ -33,64 +51,112 @@
</license>
</licenses>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
<scope>provided</scope>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.0.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.5.0</version>
<version>0.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<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>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.0-rc1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</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>
@@ -102,45 +168,16 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<version>3.1</version>
<configuration>
<excludes>
<exclude>examples/*.java</exclude>
</excludes>
<source>1.6</source>
<target>1.6</target>
</configuration>
</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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -153,7 +190,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<version>2.9.1</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
@@ -169,23 +206,77 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.5</version>
<version>2.4.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
!net.schmizz.*,
javax.crypto*,
com.jcraft.jzlib*;version="[1.0,2)",
org.slf4j*;version="[1.6,2)",
org.bouncycastle*;version="[1.4,2)",
com.jcraft.jzlib*;version="[1.1,2)";resolution:=optional,
org.slf4j*;version="[1.7,5)",
org.bouncycastle*,
*
</Import-Package>
<Export-Package>net.schmizz.*</Export-Package>
</instructions>
</configuration>
</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>
<distributionManagement>
@@ -207,58 +298,47 @@
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.0.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.24</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>release-sign-artifacts</id>
<id>doclint-java8-disable</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
<jdk>[1.8,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.3</version>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<passphrase>${gpg.passphrase}</passphrase>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.6.1</version>
</plugin>
</plugins>
</reporting>
</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

@@ -0,0 +1,39 @@
package nl.javadude.sshj.connection.channel;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
public class ChannelCloseEofTest {
private SSHClient sshClient;
@Before
public void setUp() throws Exception {
sshClient = new SSHClient();
}
@After
public void tearDown() throws IOException {
sshClient.disconnect();
}
@Test
public void shouldCorrectlyHandleSessionChannelEof() throws IOException, InterruptedException {
sshClient.addHostKeyVerifier(new PromiscuousVerifier());
sshClient.connect("172.16.37.129");
sshClient.authPassword("jeroen", "jeroen");
Session session = sshClient.startSession();
session.allocateDefaultPTY();
session.close();
Thread.sleep(1000);
assertThat("Should still be connected", sshClient.isConnected());
}
}

View File

@@ -0,0 +1,13 @@
package com.hierynomus.sshj.backport;
import java.math.BigDecimal;
public class JavaVersion {
public static boolean isJava7OrEarlier() {
String property = System.getProperty("java.specification.version");
float diff = Float.parseFloat(property) - 1.7f;
return diff < 0.01;
}
}

View File

@@ -0,0 +1,62 @@
package com.hierynomus.sshj.backport;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.Charset;
public class Jdk7HttpProxySocket extends Socket {
private Proxy httpProxy = null;
public Jdk7HttpProxySocket(Proxy proxy) {
super(proxy.type() == Proxy.Type.HTTP ? Proxy.NO_PROXY : proxy);
if (proxy.type() == Proxy.Type.HTTP) {
this.httpProxy = proxy;
}
}
@Override
public void connect(SocketAddress endpoint, int timeout) throws IOException {
if (httpProxy != null) {
connectHttpProxy(endpoint, timeout);
} else {
super.connect(endpoint, timeout);
}
}
private void connectHttpProxy(SocketAddress endpoint, int timeout) throws IOException {
super.connect(httpProxy.address(), timeout);
if (!(endpoint instanceof InetSocketAddress)) {
throw new SocketException("Expected an InetSocketAddress to connect to, got: " + endpoint);
}
InetSocketAddress isa = (InetSocketAddress) endpoint;
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
getOutputStream().write(httpConnect.getBytes(Charset.forName("UTF-8")));
checkAndFlushProxyResponse();
}
private void checkAndFlushProxyResponse()throws IOException {
InputStream socketInput = getInputStream();
byte[] tmpBuffer = new byte[512];
int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);
if (len == 0) {
throw new SocketException("Empty response from proxy");
}
String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");
// Expecting HTTP/1.x 200 OK
if (proxyResponse.contains("200")) {
// Flush any outstanding message in buffer
if (socketInput.available() > 0) {
socketInput.skip(socketInput.available());
}
// Proxy Connect Successful
} else {
throw new SocketException("Fail to create Socket\nResponse was:" + proxyResponse);
}
}
}

View File

@@ -0,0 +1,26 @@
package com.hierynomus.sshj.backport;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
public class Sockets {
/**
* Java 7 and up have Socket implemented as Closeable, whereas Java6 did not have this inheritance.
* @param socket The socket to wrap as Closeable
* @return
*/
public static Closeable asCloseable(final Socket socket) {
if (Closeable.class.isAssignableFrom(socket.getClass())) {
return Closeable.class.cast(socket);
} else {
return new Closeable() {
@Override
public void close() throws IOException {
socket.close();
}
};
}
}
}

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");
* 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");
* 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");
* 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");
* you may not use this file except in compliance with the License.
@@ -162,11 +162,14 @@ public class Promise<V, T extends Throwable> {
if (val != null)
return val;
log.debug("Awaiting <<{}>>", name);
while (val == null && pendingEx == null)
if (timeout == 0)
if (timeout == 0) {
while (val == null && pendingEx == null) {
cond.await();
else if (!cond.await(timeout, unit))
}
} else {
if (!cond.await(timeout, unit))
return null;
}
if (pendingEx != null) {
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
throw pendingEx;
@@ -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. */
public boolean hasWaiters() {
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,76 @@
/**
* 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 {
// Ensure the service is set... This means that the key exchange is done and the connection is up.
if (conn.equals(conn.getTransport().getService())) {
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");
* you may not use this file except in compliance with the License.
@@ -35,13 +35,10 @@ public abstract class AbstractService
protected final String name;
/** Transport layer */
protected final Transport trans;
/** Timeout for blocking operations */
protected int timeout;
public AbstractService(String name, Transport trans) {
this.name = name;
this.trans = trans;
timeout = trans.getTimeout();
}
@Override
@@ -77,12 +74,6 @@ public abstract class AbstractService
trans.reqService(this);
}
public int getTimeout() {
return this.timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}

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");
* 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");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.signature.Signature;
import net.schmizz.sshj.transport.cipher.Cipher;
@@ -54,16 +55,16 @@ public interface Config {
List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories();
/**
* Retrieve the list of named factories for <code>KeyExchange</code>.
* Retrieve the list of named factories for {@code KeyExchange}.
*
* @return a list of named <code>KeyExchange</code> factories
* @return a list of named {@code KeyExchange} factories
*/
List<Factory.Named<KeyExchange>> getKeyExchangeFactories();
/**
* Retrieve the list of named factories for <code>MAC</code>.
* Retrieve the list of named factories for {@code MAC}.
*
* @return a list of named <code>MAC</code> factories
* @return a list of named {@code MAC} factories
*/
List<Factory.Named<MAC>> getMACFactories();
@@ -144,4 +145,14 @@ public interface Config {
*/
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");
* 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.
* See the License for the specific language governing permissions and
* 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;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.signature.Signature;
import net.schmizz.sshj.transport.cipher.Cipher;
@@ -54,6 +35,7 @@ public class ConfigImpl
private String version;
private Factory<Random> randomFactory;
private KeepAliveProvider keepAliveProvider;
private List<Factory.Named<KeyExchange>> kexFactories;
private List<Factory.Named<Cipher>> cipherFactories;
@@ -166,4 +148,13 @@ public class ConfigImpl
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");
* 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.
* See the License for the specific language governing permissions and
* 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;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.signature.SignatureDSA;
import net.schmizz.sshj.signature.SignatureECDSA;
import net.schmizz.sshj.signature.SignatureRSA;
import net.schmizz.sshj.transport.cipher.AES128CBC;
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.HMACSHA1;
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.JCERandom;
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,18 +55,23 @@ import java.util.LinkedList;
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.
* <p/>
* <ul> <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li> <li>{@link
* ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR}, {@link
* AES128CBC}, {@link AES192CBC}, {@link AES256CBC}, {@link AES192CBC}, {@link TripleDESCBC}, {@link BlowfishCBC}</li>
* <li>{@link ConfigImpl#setMACFactories MAC}: {@link HMACSHA1}, {@link HMACSHA196}, {@link HMACMD5}, {@link
* HMACMD596}</li> <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li> <li>{@link
* ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li> <li>{@link
* ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li> <li>{@link
* ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link OpenSSHKeyFile}*</li>
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li> </ul>
* <ul>
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyExchangeFactories Key exchange}: {@link net.schmizz.sshj.transport.kex.DHG14}*, {@link net.schmizz.sshj.transport.kex.DHG1}</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},
* {@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>
* <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
* net.schmizz.sshj.transport.mac.HMACMD596}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
* <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/>
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
* prevents using ciphers with strength greater than 128.
@@ -91,7 +81,7 @@ public class DefaultConfig
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() {
setVersion(VERSION);
@@ -103,6 +93,7 @@ public class DefaultConfig
initCompressionFactories();
initMACFactories();
initSignatureFactories();
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
}
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
@@ -113,12 +104,13 @@ public class DefaultConfig
}
protected void initRandomFactory(boolean bouncyCastleRegistered) {
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered ? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered
? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
}
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
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() {
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory());
setSignatureFactories(new SignatureECDSA.Factory(), new SignatureRSA.Factory(), new SignatureDSA.Factory());
}
protected void initMACFactories() {
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() {

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");
* 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
* limitations under the License.
*/
package net.schmizz.sshj;
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.UserAuthImpl;
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.KeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
@@ -64,10 +64,11 @@ import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.ServerSocket;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
@@ -92,8 +93,8 @@ import java.util.List;
* <em>A simple example:</em>
* <p/>
* <pre>
* client = new SSHClient();
* client.initUserKnownHosts();
* final SSHClient client = new SSHClient();
* client.loadKnownHosts();
* client.connect(&quot;hostname&quot;);
* try {
* client.authPassword(&quot;username&quot;, &quot;password&quot;);
@@ -103,8 +104,9 @@ import java.util.List;
* cmd.join(1, TimeUnit.SECONDS);
* } finally {
* session.close();
* } finally {
* client.disconnect();
* }
* } finally {
* client.disconnect();
* }
* </pre>
* <p/>
@@ -142,9 +144,9 @@ public class SSHClient
*/
public SSHClient(Config config) {
super(DEFAULT_PORT);
this.trans = new TransportImpl(config);
this.trans = new TransportImpl(config, this);
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}.
*
@@ -185,7 +189,7 @@ public class SSHClient
*/
public void auth(String username, AuthMethod... methods)
throws UserAuthException, TransportException {
assert isConnected();
checkConnected();
auth(username, Arrays.<AuthMethod>asList(methods));
}
@@ -200,8 +204,17 @@ public class SSHClient
*/
public void auth(String username, Iterable<AuthMethod> methods)
throws UserAuthException, TransportException {
assert isConnected();
auth.authenticate(username, (Service) conn, methods);
checkConnected();
final Deque<UserAuthException> savedEx = new LinkedList<UserAuthException>();
for (AuthMethod method: methods) {
try {
if (auth.authenticate(username, (Service) conn, method, trans.getTimeoutMs()))
return;
} catch (UserAuthException e) {
savedEx.push(e);
}
}
throw new UserAuthException("Exhausted available authentication methods", savedEx.peek());
}
/**
@@ -296,8 +309,7 @@ public class SSHClient
* @throws TransportException if there was a transport-layer error
*/
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
throws UserAuthException,
TransportException {
throws UserAuthException, TransportException {
final List<AuthMethod> am = new LinkedList<AuthMethod>();
for (KeyProvider kp : keyProviders)
am.add(new AuthPublickey(kp));
@@ -342,13 +354,14 @@ public class SSHClient
public void authPublickey(String username, String... locations)
throws UserAuthException, TransportException {
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
for (String loc : locations)
for (String loc : locations) {
try {
log.debug("Attempting to load key from: {}", loc);
keyProviders.add(loadKeys(loc));
} catch (IOException logged) {
log.warn("Could not load keys due to: {}", logged);
log.info("Could not load keys from {} due to: {}", loc, logged.getMessage());
}
}
authPublickey(username, keyProviders);
}
@@ -362,10 +375,8 @@ public class SSHClient
@Override
public void disconnect()
throws IOException {
assert isConnected();
trans.disconnect();
super.disconnect();
assert !isConnected();
}
/** @return the associated {@link Connection} instance. */
@@ -391,8 +402,7 @@ public class SSHClient
/**
* @return the associated {@link UserAuth} instance. This allows access to information like the {@link
* UserAuth#getBanner() authentication banner}, whether authentication was at least {@link
* UserAuth#hadPartialSuccess() partially successful}, and any {@link UserAuth#getSavedExceptions() saved
* exceptions} that were ignored because there were more authentication method that could be tried.
* UserAuth#hadPartialSuccess() partially successful}.
*/
public UserAuth getUserAuth() {
return auth;
@@ -475,9 +485,9 @@ public class SSHClient
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
throws IOException {
final File loc = new File(location);
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
.toString());
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(loc);
final FileKeyProvider fkp =
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
if (fkp == null)
throw new SSHException("No provider available for " + format + " key file");
fkp.init(loc, passwordFinder);
@@ -519,9 +529,9 @@ public class SSHClient
*/
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
throws IOException {
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
.toString());
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
final FileKeyProvider fkp =
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
if (fkp == null)
throw new SSHException("No provider available for " + format + " key file");
fkp.init(privateKey, publicKey, passwordFinder);
@@ -568,23 +578,21 @@ public class SSHClient
}
/**
* Create a {@link LocalPortForwarder} that will listen on {@code address} and forward incoming connections to the
* server; which will further forward them to {@code host:port}.
* Create a {@link LocalPortForwarder} that will listen based on {@code parameters} using the bound
* {@code serverSocket} and forward incoming connections to the server; which will further forward them to
* {@code host:port}.
* <p/>
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
* listening, this method just creates an instance.
*
* @param address defines where the {@link LocalPortForwarder} listens
* @param host hostname to which the server will forward
* @param port the port at {@code hostname} to which the server wil forward
* @param parameters parameters for the forwarding setup
* @param serverSocket bound server socket
*
* @return a {@link LocalPortForwarder}
*
* @throws IOException if there is an error opening a local server socket
*/
public LocalPortForwarder newLocalPortForwarder(SocketAddress address, String host, int port)
throws IOException {
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
ServerSocket serverSocket) {
return new LocalPortForwarder(conn, parameters, serverSocket);
}
/**
@@ -609,7 +617,8 @@ public class SSHClient
/** @return Instantiated {@link SCPFileTransfer} implementation. */
public SCPFileTransfer newSCPFileTransfer() {
assert isConnected() && isAuthenticated();
checkConnected();
checkAuthenticated();
return new SCPFileTransfer(this);
}
@@ -621,7 +630,8 @@ public class SSHClient
*/
public SFTPClient newSFTPClient()
throws IOException {
assert isConnected() && isAuthenticated();
checkConnected();
checkAuthenticated();
return new SFTPClient(new SFTPEngine(this).init());
}
@@ -638,10 +648,10 @@ public class SSHClient
@Override
public Session startSession()
throws ConnectionException, TransportException {
assert isConnected() && isAuthenticated();
checkConnected();
checkAuthenticated();
final SessionChannel sess = new SessionChannel(conn);
sess.open();
assert sess.isOpen();
return sess;
}
@@ -681,11 +691,10 @@ public class SSHClient
*/
protected void doKex()
throws TransportException {
assert trans.isRunning();
checkConnected();
final long start = System.currentTimeMillis();
trans.doKex();
log.info("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
log.debug("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
}
/**
@@ -699,4 +708,16 @@ public class SSHClient
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");
* 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");
* you may not use this file except in compliance with the License.
@@ -12,40 +12,22 @@
* 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.
*
* 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;
import javax.net.ServerSocketFactory;
import com.hierynomus.sshj.backport.JavaVersion;
import com.hierynomus.sshj.backport.Jdk7HttpProxySocket;
import javax.net.SocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
abstract class SocketClient {
public abstract class SocketClient {
private final int defaultPort;
@@ -54,7 +36,6 @@ abstract class SocketClient {
private OutputStream output;
private SocketFactory socketFactory = SocketFactory.getDefault();
private ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault();
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
@@ -67,21 +48,53 @@ abstract class SocketClient {
this.defaultPort = defaultPort;
}
public void connect(InetAddress host, int port)
throws IOException {
public void connect(InetAddress host, int port) throws IOException {
socket = socketFactory.createSocket();
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(String hostname, int port)
throws IOException {
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
* @param port The port to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(InetAddress host, int port, Proxy proxy) throws IOException {
if (JavaVersion.isJava7OrEarlier() && proxy.type() == Proxy.Type.HTTP) {
// Java7 and earlier have no support for HTTP Connect proxies, return our custom socket.
socket = new Jdk7HttpProxySocket(proxy);
} else {
socket = new Socket(proxy);
}
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(String hostname, int port) throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port);
}
public void connect(InetAddress host, int port,
InetAddress localAddr, int localPort)
/**
* Connect to a host via a proxy.
* @param hostname The host name to connect to.
* @param port The port to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket(java.net.Proxy)} constructor.
*/
@Deprecated
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, InetAddress localAddr, int localPort)
throws IOException {
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
@@ -89,25 +102,44 @@ abstract class SocketClient {
onConnect();
}
public void connect(String hostname, int port,
InetAddress localAddr, int localPort)
throws IOException {
public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port, localAddr, localPort);
}
public void connect(InetAddress host)
throws IOException {
public void connect(InetAddress host) throws IOException {
connect(host, defaultPort);
}
public void connect(String hostname)
throws IOException {
public void connect(String hostname) throws IOException {
connect(hostname, defaultPort);
}
public void disconnect()
throws IOException {
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(InetAddress host, Proxy proxy) throws IOException {
connect(host, defaultPort, proxy);
}
/**
* Connect to a host via a proxy.
* @param hostname The host name to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(String hostname, Proxy proxy) throws IOException {
connect(hostname, defaultPort, proxy);
}
public void disconnect() throws IOException {
if (socket != null) {
socket.close();
socket = null;
@@ -130,7 +162,6 @@ abstract class SocketClient {
return socket.getLocalPort();
}
public InetAddress getLocalAddress() {
return socket.getLocalAddress();
}
@@ -148,27 +179,17 @@ abstract class SocketClient {
}
public void setSocketFactory(SocketFactory factory) {
if (factory == null)
if (factory == null) {
socketFactory = SocketFactory.getDefault();
else
} else {
socketFactory = factory;
}
}
public SocketFactory getSocketFactory() {
return socketFactory;
}
public void setServerSocketFactory(ServerSocketFactory factory) {
if (factory == null)
serverSocketFactory = ServerSocketFactory.getDefault();
else
serverSocketFactory = factory;
}
public ServerSocketFactory getServerSocketFactory() {
return serverSocketFactory;
}
public int getConnectTimeout() {
return connectTimeout;
}
@@ -197,11 +218,10 @@ abstract class SocketClient {
return output;
}
void onConnect()
throws IOException {
void onConnect() throws IOException {
socket.setSoTimeout(timeout);
input = socket.getInputStream();
output = socket.getOutputStream();
}
}
}

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;

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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -51,7 +31,7 @@ public class Buffer<T extends Buffer<T>> {
}
}
public static class PlainBuffer
public static final class PlainBuffer
extends Buffer<PlainBuffer> {
public PlainBuffer() {
@@ -74,10 +54,15 @@ public class Buffer<T extends Buffer<T>> {
/** The default size for a {@code Buffer} (256 bytes) */
public static final int DEFAULT_SIZE = 256;
/** The maximum valid size of buffer (i.e. biggest power of two that can be represented as an int - 2^30) */
public static final int MAX_SIZE = (1 << 30);
protected static int getNextPowerOf2(int i) {
int j = 1;
while (j < i)
while (j < i) {
j <<= 1;
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
}
return j;
}

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");
* 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.
* See the License for the specific language governing permissions and
* 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;

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");
* 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");
* 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");
* 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.
* See the License for the specific language governing permissions and
* 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;

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");
* 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.
* See the License for the specific language governing permissions and
* 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;

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");
* you may not use this file except in compliance with the License.
@@ -15,21 +15,25 @@
*/
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.security.GeneralSecurityException;
import java.security.Key;
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.*;
import java.security.interfaces.*;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
/** Type of key e.g. rsa, dsa */
public enum KeyType {
/** SSH identifier for RSA keys */
RSA("ssh-rsa") {
@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 */
UNKNOWN("unknown") {
@Override
@@ -113,10 +200,11 @@ public enum KeyType {
protected boolean isMyType(Key key) {
return false;
}
};
private static final String NISTP_CURVE = "nistp256";
protected final String sType;
private KeyType(String type) {
@@ -149,4 +237,4 @@ public enum KeyType {
return sType;
}
}
}

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");
* 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");
* 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.
* See the License for the specific language governing permissions and
* 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;

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");
* 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.
* See the License for the specific language governing permissions and
* 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;
import java.util.Arrays;
public class SSHPacket
public final class SSHPacket
extends Buffer<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");
* 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");
* 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.
* See the License for the specific language governing permissions and
* 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;

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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -62,11 +42,11 @@ public class SecurityUtils {
public void run()
throws Exception {
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
LOG.info("Trying to register BouncyCastle as a JCE provider");
LOG.debug("Trying to register BouncyCastle as a JCE provider");
java.security.Security.addProvider(new BouncyCastleProvider());
MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
LOG.info("Registration succeeded");
LOG.info("BouncyCastle registration succeeded");
} else
LOG.info("BouncyCastle already registered as a JCE provider");
securityProvider = BOUNCY_CASTLE;

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");
* you may not use this file except in compliance with the License.
@@ -107,7 +107,7 @@ public class StreamCopier {
log.debug("Done copying from {}", in);
doneEvent.set();
} catch (IOException ioe) {
log.error("In pipe from {} to {}: " + ioe.toString(), in, out);
log.error("In pipe from {} to {}: {}", in, out, ioe);
doneEvent.deliverError(ioe);
}
}
@@ -136,7 +136,7 @@ public class StreamCopier {
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
final double sizeKiB = count / 1024.0;
log.info(sizeKiB + " KiB transferred in {} seconds ({} KiB/s)", timeSeconds, (sizeKiB / timeSeconds));
log.debug("{} KiB transferred in {} seconds ({} KiB/s)", sizeKiB, timeSeconds, (sizeKiB / timeSeconds));
if (length != -1 && read == -1)
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
@@ -154,4 +154,4 @@ public class StreamCopier {
return count;
}
}
}

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");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package net.schmizz.sshj.connection;
import net.schmizz.concurrent.Promise;
import net.schmizz.keepalive.KeepAlive;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.connection.channel.Channel;
import net.schmizz.sshj.connection.channel.OpenFailException;
@@ -125,29 +126,34 @@ public interface Connection {
void setMaxPacketSize(int maxPacketSize);
/** @return the size for the local window this connection recommends to any {@link Channel}'s that ask for it. */
int getWindowSize();
long getWindowSize();
/**
* Set the size for the local window this connection recommends to any {@link Channel}'s that ask for it.
*
* @param windowSize window size in bytes
*/
void setWindowSize(int windowSize);
void setWindowSize(long windowSize);
/** @return the associated {@link Transport}. */
Transport getTransport();
/**
* @return the {@code timeout} in seconds that this connection uses for blocking operations and recommends to any
* {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
* @return the {@code timeout} in milliseconds that this connection uses for blocking operations and recommends to
* any {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
*/
int getTimeout();
int getTimeoutMs();
/**
* Set the {@code timeout} this connection uses for blocking operations and recommends to any {@link Channel other}
* {@link ForwardedChannelOpener classes} that ask for it.
*
* @param timeout timeout in seconds
* @param timeout timeout in milliseconds
*/
void setTimeout(int timeout);
void setTimeoutMs(int timeout);
/**
* @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");
* 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");
* 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.Promise;
import net.schmizz.keepalive.KeepAlive;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.AbstractService;
import net.schmizz.sshj.common.Buffer;
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 int windowSize = 2048 * 1024;
/** {@code keep-alive} mechanism */
private final KeepAlive keepAlive;
private long windowSize = 2048 * 1024;
private int maxPacketSize = 32 * 1024;
private volatile int timeoutMs;
/**
* Create with an associated {@link Transport}.
*
* @param config the ssh config
* @param trans transport layer
* @param keepAlive
*/
public ConnectionImpl(Transport trans) {
public ConnectionImpl(Transport trans, KeepAliveProvider keepAlive) {
super("ssh-connection", trans);
timeoutMs = trans.getTimeoutMs();
this.keepAlive = keepAlive.provide(this);
}
@Override
public void attach(Channel chan) {
log.info("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
log.debug("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
channels.put(chan.getID(), chan);
}
@@ -81,7 +92,7 @@ public class ConnectionImpl
@Override
public void forget(Channel chan) {
log.info("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
log.debug("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
channels.remove(chan.getID());
synchronized (internalSynchronizer) {
if (channels.isEmpty())
@@ -91,13 +102,13 @@ public class ConnectionImpl
@Override
public void forget(ForwardedChannelOpener opener) {
log.info("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
log.debug("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
openers.remove(opener.getChannelType());
}
@Override
public void attach(ForwardedChannelOpener opener) {
log.info("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
log.debug("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
openers.put(opener.getChannelType(), opener);
}
@@ -159,12 +170,12 @@ public class ConnectionImpl
}
@Override
public int getWindowSize() {
public long getWindowSize() {
return windowSize;
}
@Override
public void setWindowSize(int windowSize) {
public void setWindowSize(long windowSize) {
this.windowSize = windowSize;
}
@@ -187,7 +198,7 @@ public class ConnectionImpl
byte[] specifics)
throws TransportException {
synchronized (globalReqPromises) {
log.info("Making global request for `{}`", name);
log.debug("Making global request for `{}`", name);
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
.putBoolean(wantReply)
.putRawBytes(specifics));
@@ -247,8 +258,24 @@ public class ConnectionImpl
ErrorDeliveryUtil.alertPromises(error, globalReqPromises);
globalReqPromises.clear();
}
keepAlive.interrupt();
ErrorNotifiable.Util.alertAll(error, channels.values());
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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -61,6 +41,8 @@ import java.util.concurrent.locks.ReentrantLock;
public abstract class AbstractChannel
implements Channel {
private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
@@ -79,15 +61,12 @@ public abstract class AbstractChannel
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
/* The lock used by to create the open & close events */
private final ReentrantLock lock = new ReentrantLock();
private final ReentrantLock openCloseLock = new ReentrantLock();
/** Channel open event */
protected final Event<ConnectionException> open;
protected final Event<ConnectionException> openEvent;
/** Channel close event */
protected final Event<ConnectionException> close;
/* Access to these fields should be synchronized using this object */
private boolean eofSent;
private boolean eofGot;
protected final Event<ConnectionException> closeEvent;
/** Whether we have already sent a CHANNEL_CLOSE request to the server */
private boolean closeRequested;
/** Local window */
@@ -112,15 +91,15 @@ public abstract class AbstractChannel
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
in = new ChannelInputStream(this, trans, lwin);
open = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, lock);
close = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, lock);
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock);
closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock);
}
protected void init(int recipient, int remoteWinSize, int remoteMaxPacketSize) {
protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) {
this.recipient = recipient;
rwin = new Window.Remote(remoteWinSize, remoteMaxPacketSize);
rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING));
out = new ChannelOutputStream(this, trans, rwin);
log.info("Initialized - {}", this);
log.debug("Initialized - {}", this);
}
@Override
@@ -144,7 +123,7 @@ public abstract class AbstractChannel
}
@Override
public int getLocalWinSize() {
public long getLocalWinSize() {
return lwin.getSize();
}
@@ -164,7 +143,7 @@ public abstract class AbstractChannel
}
@Override
public int getRemoteWinSize() {
public long getRemoteWinSize() {
return rwin.getSize();
}
@@ -218,7 +197,7 @@ public abstract class AbstractChannel
private void gotClose()
throws TransportException {
log.info("Got close");
log.debug("Got close");
try {
closeAllStreams();
sendClose();
@@ -236,7 +215,7 @@ public abstract class AbstractChannel
public void notifyError(SSHException error) {
log.debug("Channel #{} got notified of {}", getID(), error.toString());
ErrorDeliveryUtil.alertEvents(error, open, close);
ErrorDeliveryUtil.alertEvents(error, openEvent, closeEvent);
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
in.notifyError(error);
@@ -254,49 +233,53 @@ public abstract class AbstractChannel
@Override
public void close()
throws ConnectionException, TransportException {
lock.lock();
openCloseLock.lock();
try {
try {
sendClose();
} catch (TransportException e) {
if (!close.inError())
throw e;
if (isOpen()) {
try {
sendClose();
} catch (TransportException e) {
if (!closeEvent.inError())
throw e;
}
closeEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
close.await(conn.getTimeout(), TimeUnit.SECONDS);
} finally {
lock.unlock();
openCloseLock.unlock();
}
}
public void join()
throws ConnectionException {
close.await();
closeEvent.await();
}
public void join(int timeout, TimeUnit unit)
public void join(long timeout, TimeUnit unit)
throws ConnectionException {
close.await(timeout, unit);
closeEvent.await(timeout, unit);
}
protected synchronized void sendClose()
protected void sendClose()
throws TransportException {
openCloseLock.lock();
try {
if (!closeRequested) {
log.info("Sending close");
log.debug("Sending close");
trans.write(newBuffer(Message.CHANNEL_CLOSE));
}
} finally {
closeRequested = true;
openCloseLock.unlock();
}
}
@Override
public synchronized boolean isOpen() {
lock.lock();
public boolean isOpen() {
openCloseLock.lock();
try {
return open.isSet() && !close.isSet() && !closeRequested;
return openEvent.isSet() && !closeEvent.isSet() && !closeRequested;
} finally {
lock.unlock();
openCloseLock.unlock();
}
}
@@ -309,25 +292,25 @@ public abstract class AbstractChannel
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);
}
log.info("Got chan request for `{}`", reqType);
log.debug("Got chan request for `{}`", reqType);
handleRequest(reqType, buf);
}
private void gotWindowAdjustment(SSHPacket buf)
throws ConnectionException {
final int howMuch;
final long howMuch;
try {
howMuch = buf.readUInt32AsInt();
howMuch = buf.readUInt32();
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);
}
log.info("Received window adjustment for {} bytes", howMuch);
log.debug("Received window adjustment for {} bytes", howMuch);
rwin.expand(howMuch);
}
protected void finishOff() {
conn.forget(this);
close.set();
closeEvent.set();
}
protected void gotExtendedData(SSHPacket buf)
@@ -367,7 +350,7 @@ public abstract class AbstractChannel
protected Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
Buffer.PlainBuffer reqSpecific)
throws TransportException {
log.info("Sending channel request for `{}`", reqType);
log.debug("Sending channel request for `{}`", reqType);
synchronized (chanReqResponseEvents) {
trans.write(
newBuffer(Message.CHANNEL_REQUEST)
@@ -379,7 +362,7 @@ public abstract class AbstractChannel
Event<ConnectionException> responseEvent = null;
if (wantReply) {
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
ConnectionException.chainer);
ConnectionException.chainer);
chanReqResponseEvents.add(responseEvent);
}
return responseEvent;
@@ -397,17 +380,14 @@ public abstract class AbstractChannel
responseEvent.deliverError(new ConnectionException("Request failed"));
} else
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 {
log.info("Got EOF");
eofGot = true;
log.debug("Got EOF");
eofInputStreams();
if (eofSent)
sendClose();
}
/** Called when EOF has been received. Subclasses can override but must call super. */
@@ -415,22 +395,6 @@ public abstract class AbstractChannel
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
public String toString() {
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");
* you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ public interface Channel
int getLocalMaxPacketSize();
/** @return the current local window size. */
int getLocalWinSize();
long getLocalWinSize();
/** @return an {@code OutputStream} for this channel. */
OutputStream getOutputStream();
@@ -111,7 +111,7 @@ public interface Channel
int getRemoteMaxPacketSize();
/** @return the current remote window size. */
int getRemoteWinSize();
long getRemoteWinSize();
/** @return the channel type identifier. */
String getType();
@@ -119,15 +119,6 @@ public interface Channel
/** @return whether the channel is open. */
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
* 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()
throws ConnectionException;
void join(int timeout, TimeUnit unit)
void join(long timeout, TimeUnit unit)
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");
* 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.
* See the License for the specific language governing permissions and
* 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;
import net.schmizz.sshj.common.Buffer;
@@ -159,9 +138,9 @@ public final class ChannelInputStream
private void checkWindow()
throws TransportException {
synchronized (win) {
final int adjustment = win.neededAdjustment();
final long adjustment = win.neededAdjustment();
if (adjustment > 0) {
log.info("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
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");
* 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.
* See the License for the specific language governing permissions and
* 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;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.ErrorNotifiable;
import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
import java.io.IOException;
import java.io.OutputStream;
@@ -56,26 +38,99 @@ public final class ChannelOutputStream
private final Channel chan;
private final Transport trans;
private final Window.Remote win;
private final SSHPacket buffer = new SSHPacket();
private final DataBuffer buffer = new DataBuffer();
private final byte[] b = new byte[1];
private int bufferLength;
private boolean closed;
private SSHException error;
private final class DataBuffer {
private final int headerOffset;
private final int dataOffset;
private final SSHPacket packet = new SSHPacket(Message.CHANNEL_DATA);
private final Buffer.PlainBuffer leftOvers = new Buffer.PlainBuffer();
DataBuffer() {
headerOffset = packet.rpos();
packet.putUInt32(0); // recipient
packet.putUInt32(0); // data length
dataOffset = packet.wpos();
}
int write(byte[] data, int off, int len)
throws TransportException, ConnectionException {
final int bufferSize = packet.wpos() - dataOffset;
if (bufferSize >= win.getMaxPacketSize()) {
flush(bufferSize, 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) {
this.chan = chan;
this.trans = trans;
this.win = win;
prepBuffer();
}
private void prepBuffer() {
bufferLength = 0;
buffer.rpos(5);
buffer.wpos(5);
buffer.putMessageID(Message.CHANNEL_DATA);
buffer.putUInt32(0); // meant to be recipient
buffer.putUInt32(0); // meant to be data length
}
@Override
@@ -86,19 +141,13 @@ public final class ChannelOutputStream
}
@Override
public synchronized void write(byte[] data, int off, int len)
public synchronized void write(final byte[] data, int off, int len)
throws IOException {
checkClose();
while (len > 0) {
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
if (x <= 0) {
flush();
continue;
}
buffer.putRawBytes(data, off, x);
bufferLength += x;
off += x;
len -= x;
final int n = buffer.write(data, off, len);
off += n;
len -= n;
}
}
@@ -107,55 +156,40 @@ public final class ChannelOutputStream
this.error = error;
}
private synchronized void checkClose()
private void checkClose()
throws SSHException {
if (closed)
if (closed) {
if (error != null)
throw error;
else
throw new ConnectionException("Stream closed");
}
}
@Override
public synchronized void close()
throws IOException {
if (!closed)
if (!closed) {
try {
flush();
chan.sendEOF();
buffer.flush(false);
// trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
} finally {
setClosed();
closed = true;
}
}
}
public synchronized void setClosed() {
closed = true;
}
/**
* Send all data currently buffered. If window space is exhausted in the process, this will block
* until it is expanded by the server.
*
* @throws IOException
*/
@Override
public synchronized void flush()
throws IOException {
checkClose();
if (bufferLength <= 0) // No data to send
return;
putRecipientAndLength();
try {
win.waitAndConsume(bufferLength);
trans.write(buffer);
} finally {
prepBuffer();
}
}
private void putRecipientAndLength() {
final int origPos = buffer.wpos();
buffer.wpos(6);
buffer.putUInt32(chan.getRecipient());
buffer.putUInt32(bufferLength);
buffer.wpos(origPos);
buffer.flush(true);
}
@Override
@@ -163,4 +197,4 @@ public final class ChannelOutputStream
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
}
}
}

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");
* 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");
* you may not use this file except in compliance with the License.
@@ -18,11 +18,12 @@ package net.schmizz.sshj.connection.channel;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.IOUtils;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class SocketStreamCopyMonitor
extends Thread {
@@ -32,16 +33,6 @@ public class SocketStreamCopyMonitor
setDaemon(true);
}
private static Closeable wrapSocket(final Socket socket) {
return new Closeable() {
@Override
public void close()
throws IOException {
socket.close();
}
};
}
public static void monitor(final int frequency, final TimeUnit unit,
final Event<IOException> x, final Event<IOException> y,
final Channel channel, final Socket socket) {
@@ -54,7 +45,7 @@ public class SocketStreamCopyMonitor
}
} catch (IOException ignored) {
} finally {
IOUtils.closeQuietly(channel, wrapSocket(socket));
IOUtils.closeQuietly(channel, asCloseable(socket));
}
}
}).start();

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");
* you may not use this file except in compliance with the License.
@@ -28,17 +28,17 @@ public abstract class Window {
protected final int maxPacketSize;
protected int size;
protected long size;
public Window(int initialWinSize, int maxPacketSize) {
public Window(long initialWinSize, int maxPacketSize) {
size = initialWinSize;
this.maxPacketSize = maxPacketSize;
}
public void expand(int inc) {
public void expand(long inc) {
synchronized (lock) {
log.debug("Increasing by {} up to {}", inc, size);
size += inc;
log.debug("Increasing by {} up to {}", inc, size);
lock.notifyAll();
}
}
@@ -47,15 +47,17 @@ public abstract class Window {
return maxPacketSize;
}
public int getSize() {
return size;
public long getSize() {
synchronized (lock) {
return size;
}
}
public void consume(int dec)
public void consume(long dec)
throws ConnectionException {
synchronized (lock) {
log.debug("Consuming by " + dec + " down to " + size);
size -= dec;
log.debug("Consuming by {} down to {}", dec, size);
if (size < 0)
throw new ConnectionException("Window consumed to below 0");
}
@@ -70,29 +72,29 @@ public abstract class Window {
public static final class Remote
extends Window {
public Remote(int initialWinSize, int maxPacketSize) {
public Remote(long initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
}
public void waitAndConsume(int howMuch)
public long awaitExpansion(long was)
throws ConnectionException {
synchronized (lock) {
while (size < howMuch) {
log.debug("Waiting, need window space for {} bytes", howMuch);
while (size <= was) {
log.debug("Waiting, need size to grow from {} bytes", was);
try {
lock.wait();
} catch (InterruptedException ie) {
throw new ConnectionException(ie);
}
}
consume(howMuch);
return size;
}
}
public void consume(int howMuch) {
public void consume(long howMuch) {
try {
super.consume(howMuch);
} catch (ConnectionException e) {
} catch (ConnectionException e) { // It's a bug if we consume more than remote allowed
throw new SSHRuntimeException(e);
}
}
@@ -103,18 +105,18 @@ public abstract class Window {
public static final class Local
extends Window {
private final int initialSize;
private final int threshold;
private final long initialSize;
private final long threshold;
public Local(int initialWinSize, int maxPacketSize) {
public Local(long initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
this.initialSize = initialWinSize;
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
}
public int neededAdjustment() {
public long neededAdjustment() {
synchronized (lock) {
return (size - threshold <= 0) ? (initialSize - size) : 0;
return (size <= threshold) ? (initialSize - size) : 0;
}
}

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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -65,23 +45,23 @@ public abstract class AbstractDirectChannel
public void open()
throws ConnectionException, TransportException {
trans.write(buildOpenReq());
open.await(conn.getTimeout(), TimeUnit.SECONDS);
openEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
private void gotOpenConfirmation(SSHPacket buf)
throws ConnectionException {
try {
init(buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt());
init(buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32());
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);
}
open.set();
openEvent.set();
}
private void gotOpenFailure(SSHPacket buf)
throws ConnectionException {
try {
open.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
openEvent.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);
}

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");
* you may not use this file except in compliance with the License.
@@ -16,107 +16,113 @@
package net.schmizz.sshj.connection.channel.direct;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ServerSocketFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class LocalPortForwarder {
private class DirectTCPIPChannel
extends AbstractDirectChannel {
public static class Parameters {
private final Socket sock;
private final String localHost;
private final int localPort;
private final String remoteHost;
private final int remotePort;
private DirectTCPIPChannel(Connection conn, Socket sock) {
super(conn, "direct-tcpip");
this.sock = sock;
public Parameters(String localHost, int localPort, String remoteHost, int remotePort) {
this.localHost = localHost;
this.localPort = localPort;
this.remoteHost = remoteHost;
this.remotePort = remotePort;
}
private void start()
public String getRemoteHost() {
return remoteHost;
}
public int getRemotePort() {
return remotePort;
}
public String getLocalHost() {
return localHost;
}
public int getLocalPort() {
return localPort;
}
}
public static class DirectTCPIPChannel
extends AbstractDirectChannel {
protected final Socket socket;
protected final Parameters parameters;
public DirectTCPIPChannel(Connection conn, Socket socket, Parameters parameters) {
super(conn, "direct-tcpip");
this.socket = socket;
this.parameters = parameters;
}
protected void start()
throws IOException {
sock.setSendBufferSize(getLocalMaxPacketSize());
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), getOutputStream())
socket.setSendBufferSize(getLocalMaxPacketSize());
socket.setReceiveBufferSize(getRemoteMaxPacketSize());
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream())
.bufSize(getRemoteMaxPacketSize())
.spawnDaemon("soc2chan");
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), sock.getOutputStream())
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream())
.bufSize(getLocalMaxPacketSize())
.spawnDaemon("chan2soc");
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, sock);
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
}
@Override
protected SSHPacket buildOpenReq() {
return super.buildOpenReq()
.putString(host)
.putUInt32(port)
.putString(ss.getInetAddress().getHostAddress())
.putUInt32(ss.getLocalPort());
.putString(parameters.getRemoteHost())
.putUInt32(parameters.getRemotePort())
.putString(parameters.getLocalHost())
.putUInt32(parameters.getLocalPort());
}
}
private final Logger log = LoggerFactory.getLogger(getClass());
private final Logger log = LoggerFactory.getLogger(LocalPortForwarder.class);
private final Connection conn;
private final ServerSocket ss;
private final String host;
private final int port;
private final Parameters parameters;
private final ServerSocket serverSocket;
/**
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
* listening unless {@link #listen() explicitly told to}. The {@link javax.net.ServerSocketFactory#getDefault()
* default} server socket factory is used.
*
* @param conn {@link Connection} implementation
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
* and valid local address will be picked to bind the server socket
* @param host what host the SSH server will further forward to
* @param port port on {@code toHost}
*
* @throws IOException if there is an error binding on specified {@code listeningAddr}
*/
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port)
throws IOException {
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
}
/**
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
* listening unless {@link #listen() explicitly told to}.
*
* @param ssf factory to use for creating the server socket
* @param conn {@link Connection} implementation
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
* and valid local address will be picked to bind the server socket
* @param host what host the SSH server will further forward to
* @param port port on {@code toHost}
*
* @throws IOException if there is an error binding on specified {@code listeningAddr}
*/
public LocalPortForwarder(ServerSocketFactory ssf, Connection conn, SocketAddress listeningAddr, String host, int port)
throws IOException {
public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket) {
this.conn = conn;
this.host = host;
this.port = port;
this.ss = ssf.createServerSocket();
ss.setReceiveBufferSize(conn.getMaxPacketSize());
ss.bind(listeningAddr);
this.parameters = parameters;
this.serverSocket = serverSocket;
}
/** @return the address to which this forwarder is bound for listening */
public SocketAddress getListeningAddress() {
return ss.getLocalSocketAddress();
private void startChannel(Socket socket) throws IOException {
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
try {
chan.open();
chan.start();
} catch (IOException e) {
IOUtils.closeQuietly(chan, asCloseable(socket));
throw e;
}
}
/**
@@ -126,16 +132,13 @@ public class LocalPortForwarder {
*/
public void listen()
throws IOException {
log.info("Listening on {}", ss.getLocalSocketAddress());
Socket sock;
log.info("Listening on {}", serverSocket.getLocalSocketAddress());
while (!Thread.currentThread().isInterrupted()) {
sock = ss.accept();
log.info("Got connection from {}", sock.getRemoteSocketAddress());
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, sock);
chan.open();
chan.start();
final Socket socket = serverSocket.accept();
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
startChannel(socket);
}
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");
* 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");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.Channel;
import net.schmizz.sshj.transport.TransportException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
@@ -81,14 +80,6 @@ public interface Session
void signal(Signal signal)
throws TransportException;
@Deprecated
String getOutputAsString()
throws IOException;
@Deprecated
String getErrorAsString()
throws IOException;
}
/** 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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -46,7 +26,6 @@ import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.ChannelInputStream;
import net.schmizz.sshj.transport.TransportException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
@@ -59,13 +38,13 @@ public class SessionChannel
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
private Integer exitStatus;
private volatile Integer exitStatus;
private Signal exitSignal;
private Boolean wasCoreDumped;
private String exitErrMsg;
private volatile Signal exitSignal;
private volatile Boolean wasCoreDumped;
private volatile String exitErrMsg;
private Boolean canDoFlowControl;
private volatile Boolean canDoFlowControl;
private boolean usedUp;
@@ -76,7 +55,7 @@ public class SessionChannel
@Override
public void allocateDefaultPTY()
throws ConnectionException, TransportException {
allocatePTY("dummy", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
}
@Override
@@ -92,7 +71,7 @@ public class SessionChannel
.putUInt32(width)
.putUInt32(height)
.putBytes(PTYMode.encode(modes))
).await(conn.getTimeout(), TimeUnit.SECONDS);
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
@Override
@@ -118,9 +97,9 @@ public class SessionChannel
public Command exec(String command)
throws ConnectionException, TransportException {
checkReuse();
log.info("Will request to exec `{}`", command);
log.debug("Will request to exec `{}`", command);
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
.await(conn.getTimeout(), TimeUnit.SECONDS);
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
usedUp = true;
return this;
}
@@ -176,14 +155,14 @@ public class SessionChannel
.putString(authProto)
.putString(authCookie)
.putUInt32(screen)
).await(conn.getTimeout(), TimeUnit.SECONDS);
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
@Override
public void setEnvVar(String name, String value)
throws ConnectionException, TransportException {
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
.await(conn.getTimeout(), TimeUnit.SECONDS);
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
@Override
@@ -196,7 +175,7 @@ public class SessionChannel
public Shell startShell()
throws ConnectionException, TransportException {
checkReuse();
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
sendChannelRequest("shell", true, null).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
usedUp = true;
return this;
}
@@ -207,7 +186,7 @@ public class SessionChannel
checkReuse();
log.info("Will request `{}` subsystem", name);
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
.await(conn.getTimeout(), TimeUnit.SECONDS);
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
usedUp = true;
return this;
}
@@ -255,18 +234,4 @@ public class SessionChannel
throw new SSHRuntimeException("This session channel is all used up");
}
@Override
@Deprecated
public String getOutputAsString()
throws IOException {
return IOUtils.readFully(getInputStream()).toString();
}
@Override
@Deprecated
public String getErrorAsString()
throws IOException {
return IOUtils.readFully(getErrorStream()).toString();
}
}

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");
* 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");
* 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
* limitations under the License.
*/
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. */

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");
* 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.
* See the License for the specific language governing permissions and
* 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;
@@ -54,8 +34,9 @@ public abstract class AbstractForwardedChannel
* First 2 args are standard; the others can be parsed from a CHANNEL_OPEN packet.
*/
protected AbstractForwardedChannel(Connection conn, String type, int recipient, int remoteWinSize,
int remoteMaxPacketSize, String origIP, int origPort) {
protected AbstractForwardedChannel(Connection conn, String type,
int recipient, long remoteWinSize, long remoteMaxPacketSize,
String origIP, int origPort) {
super(conn, type);
this.origIP = origIP;
this.origPort = origPort;
@@ -65,20 +46,20 @@ public abstract class AbstractForwardedChannel
@Override
public void confirm()
throws TransportException {
log.info("Confirming `{}` channel #{}", getType(), getID());
log.debug("Confirming `{}` channel #{}", getType(), getID());
// Must ensure channel is attached before confirming, data could start coming in immediately!
conn.attach(this);
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
.putUInt32(getID())
.putUInt32(getLocalWinSize())
.putUInt32(getLocalMaxPacketSize()));
open.set();
openEvent.set();
}
@Override
public void reject(Reason reason, String message)
throws TransportException {
log.info("Rejecting `{}` channel: {}", getType(), message);
log.debug("Rejecting `{}` channel: {}", getType(), message);
conn.sendOpenFailure(getRecipient(), reason, message);
}

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");
* 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
* limitations under the License.
*/
package net.schmizz.sshj.connection.channel.forwarded;
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");
* 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");
* 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");
* you may not use this file except in compliance with the License.
@@ -127,7 +127,8 @@ public class RemotePortForwarder
private final Forward fwd;
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
public ForwardedTCPIPChannel(Connection conn,
int recipient, long remoteWinSize, long remoteMaxPacketSize,
Forward fwd, String origIP, int origPort) {
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
this.fwd = fwd;
@@ -200,7 +201,7 @@ public class RemotePortForwarder
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
.getCompactData();
return conn.sendGlobalRequest(reqName, true, specifics)
.retrieve(conn.getTimeout(), TimeUnit.SECONDS);
.retrieve(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
}
/** @return the active forwards. */
@@ -217,7 +218,7 @@ public class RemotePortForwarder
throws ConnectionException, TransportException {
final ForwardedTCPIPChannel chan;
try {
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt(),
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
new Forward(buf.readString(), buf.readUInt32AsInt()),
buf.readString(), buf.readUInt32AsInt());
} catch (Buffer.BufferException be) {

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");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public class SocketForwardingConnectListener
@Override
public void gotConnect(Channel.Forwarded chan)
throws IOException {
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
log.debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
final Socket sock = new Socket();
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
@@ -66,4 +66,4 @@ public class SocketForwardingConnectListener
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
}
}
}

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");
* you may not use this file except in compliance with the License.
@@ -34,8 +34,9 @@ public class X11Forwarder
public static final String TYPE = "x11";
public X11Channel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize, String origIP,
int origPort) {
public X11Channel(Connection conn,
int recipient, long remoteWinSize, long remoteMaxPacketSize,
String origIP, int origPort) {
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
}
@@ -58,8 +59,7 @@ public class X11Forwarder
throws ConnectionException, TransportException {
try {
callListener(listener, new X11Channel(conn,
buf.readUInt32AsInt(),
buf.readUInt32AsInt(), buf.readUInt32AsInt(),
buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
buf.readString(), buf.readUInt32AsInt()));
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);

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");
* 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");
* 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");
* 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");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package net.schmizz.sshj.sftp;
import net.schmizz.concurrent.Promise;
import net.schmizz.sshj.common.SSHException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,24 +58,25 @@ public class PacketReader
throws IOException {
readIntoBuffer(lenBuf, 0, lenBuf.length);
return (int) (lenBuf[0] << 24 & 0xff000000L
final long len = (lenBuf[0] << 24 & 0xff000000L
| lenBuf[1] << 16 & 0x00ff0000L
| lenBuf[2] << 8 & 0x0000ff00L
| lenBuf[3] & 0x000000ffL);
if (len > SFTPPacket.MAX_SIZE) {
throw new SSHException(String.format("Indicated packet length %d too large", len));
}
return (int) len;
}
public SFTPPacket<Response> readPacket()
throws IOException {
int len = getPacketLength();
packet.rpos(0);
packet.wpos(0);
final int len = getPacketLength();
packet.clear();
packet.ensureCapacity(len);
readIntoBuffer(packet.array(), 0, len);
packet.wpos(len);
return packet;
}
@@ -102,8 +105,11 @@ public class PacketReader
promise.deliver(resp);
}
public void expectResponseTo(Request req) {
promises.put(req.getRequestID(), req.getResponsePromise());
public Promise<Response, SFTPException> expectResponseTo(long requestId) {
final Promise<Response, SFTPException> promise
= new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer);
promises.put(requestId, promise);
return promise;
}
}

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");
* 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");
* 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");
* you may not use this file except in compliance with the License.
@@ -19,15 +19,27 @@ import java.io.IOException;
public class PathHelper {
public interface Canonicalizer {
String canonicalize(String path)
throws IOException;
}
public static final String DEFAULT_PATH_SEPARATOR = "/";
private final SFTPEngine engine;
private final Canonicalizer canonicalizer;
private final String pathSep;
private String dotDir;
public PathHelper(SFTPEngine engine, String pathSep) {
this.engine = engine;
private synchronized String getDotDir() // cached
throws IOException {
return (dotDir != null) ? dotDir : (dotDir = canonicalizer.canonicalize("."));
}
public PathHelper(Canonicalizer canonicalizer, String pathSep) {
this.canonicalizer = canonicalizer;
this.pathSep = pathSep;
}
@@ -47,37 +59,33 @@ public class PathHelper {
return new PathComponents(parent, name, pathSep);
}
public PathComponents getComponents(String path)
/**
* Divide the path into {@code PathComponents(parent, name)} while making sure {@code name != "." && name != ".."}
*
* @param path to convert
*
* @return PathComponents
*
* @throws IOException
*/
public PathComponents getComponents(final String path)
throws IOException {
if (path.isEmpty() || path.equals("."))
if (path.equals(pathSep))
return getComponents("", "");
if (path.isEmpty() || path.equals(".") || path.equals("." + pathSep))
return getComponents(getDotDir());
final int lastSlash = path.lastIndexOf(pathSep);
final String withoutTrailSep = trimTrailingSeparator(path);
final int lastSep = withoutTrailSep.lastIndexOf(pathSep);
final String parent = (lastSep == -1) ? "" : withoutTrailSep.substring(0, lastSep);
final String name = (lastSep == -1) ? withoutTrailSep : withoutTrailSep.substring(lastSep + pathSep.length());
if (lastSlash == -1) // Relative path
if (path.equals(".."))
return getComponents(canon(path));
else
return getComponents(getDotDir(), path);
final String name = path.substring(lastSlash + pathSep.length());
if (name.equals(".") || name.equals(".."))
return getComponents(canon(path));
else {
final String parent = path.substring(0, lastSlash);
if (name.equals(".") || name.equals("..")) {
return getComponents(canonicalizer.canonicalize(path));
} else {
return getComponents(parent, name);
}
}
private synchronized String getDotDir()
throws IOException {
return (dotDir != null) ? dotDir : (dotDir = canon("."));
}
private String canon(String path)
throws IOException {
return engine.canonicalize(path);
}
}

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");
* 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");
* 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.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class RemoteDirectory
extends RemoteResource {
public RemoteDirectory(Requester requester, String path, String handle) {
public RemoteDirectory(Requester requester, String path, byte[] handle) {
super(requester, path, handle);
}
@@ -33,7 +34,8 @@ public class RemoteDirectory
List<RemoteResourceInfo> rri = new LinkedList<RemoteResourceInfo>();
loop:
for (; ; ) {
Response res = requester.doRequest(newRequest(PacketType.READDIR));
final Response res = requester.request(newRequest(PacketType.READDIR))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
switch (res.getType()) {
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");
* you may not use this file except in compliance with the License.
@@ -15,32 +15,30 @@
*/
package net.schmizz.sshj.sftp;
import net.schmizz.concurrent.Promise;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.sftp.Response.StatusCode;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
public class RemoteFile
extends RemoteResource {
public RemoteFile(Requester requester, String path, String handle) {
public RemoteFile(Requester requester, String path, byte[] handle) {
super(requester, path, handle);
}
public RemoteFileInputStream getInputStream() {
return new RemoteFileInputStream();
}
public RemoteFileOutputStream getOutputStream() {
return new RemoteFileOutputStream();
}
public FileAttributes fetchAttributes()
throws IOException {
return requester.doRequest(newRequest(PacketType.FSTAT))
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
return requester.request(newRequest(PacketType.FSTAT))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
public long length()
@@ -55,7 +53,17 @@ public class RemoteFile
public int read(long fileOffset, byte[] to, int offset, int len)
throws IOException {
Response res = requester.doRequest(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
final Response res = 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()) {
case DATA:
int recvLen = res.readUInt32AsInt();
@@ -73,23 +81,35 @@ public class RemoteFile
public void write(long fileOffset, byte[] data, int off, int len)
throws IOException {
requester.doRequest(newRequest(PacketType.WRITE)
.putUInt64(fileOffset)
.putUInt32(len - off)
.putRawBytes(data, off, len)
).ensureStatusPacketIsOK();
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)
// TODO The SFTP spec claims this field is unneeded...? See #187
.putUInt32(len)
.putRawBytes(data, off, len)
);
}
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise)
throws SFTPException {
responsePromise.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
public void setAttributes(FileAttributes attrs)
throws IOException {
requester.doRequest(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs)).ensureStatusPacketIsOK();
requester.request(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
public int getOutgoingPacketOverhead() {
return 1 + // packet type
4 + // request id
4 + // next length
handle.length() + // next
handle.length + // next
8 + // file offset
4 + // data length
4; // packet length
@@ -98,17 +118,25 @@ public class RemoteFile
public class RemoteFileOutputStream
extends OutputStream {
private final byte[] b = new byte[1];
private final int maxUnconfirmedWrites;
private final Queue<Promise<Response, SFTPException>> unconfirmedWrites;
private long fileOffset;
public RemoteFileOutputStream() {
this(0);
}
public RemoteFileOutputStream(long fileOffset) {
this.fileOffset = fileOffset;
public RemoteFileOutputStream(long startingOffset) {
this(startingOffset, 0);
}
public RemoteFileOutputStream(long startingOffset, int maxUnconfirmedWrites) {
this.fileOffset = startingOffset;
this.maxUnconfirmedWrites = maxUnconfirmedWrites;
this.unconfirmedWrites = new LinkedList<Promise<Response, SFTPException>>();
}
@Override
@@ -121,10 +149,27 @@ public class RemoteFile
@Override
public void write(byte[] buf, int off, int len)
throws IOException {
RemoteFile.this.write(fileOffset, buf, off, len);
if (unconfirmedWrites.size() > maxUnconfirmedWrites) {
checkWriteResponse(unconfirmedWrites.remove());
}
unconfirmedWrites.add(RemoteFile.this.asyncWrite(fileOffset, buf, off, 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
@@ -140,7 +185,7 @@ public class RemoteFile
this(0);
}
public RemoteFileInputStream(int fileOffset) {
public RemoteFileInputStream(long fileOffset) {
this.fileOffset = fileOffset;
}
@@ -186,4 +231,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");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public abstract class RemoteResource
implements Closeable {
@@ -29,9 +30,9 @@ public abstract class RemoteResource
protected final Requester requester;
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.path = path;
this.handle = handle;
@@ -48,8 +49,10 @@ public abstract class RemoteResource
@Override
public void close()
throws IOException {
log.info("Closing `{}`", this);
requester.doRequest(newRequest(PacketType.CLOSE)).ensureStatusPacketIsOK();
log.debug("Closing `{}`", this);
requester.request(newRequest(PacketType.CLOSE))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
.ensureStatusPacketIsOK();
}
@Override

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");
* 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");
* 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");
* you may not use this file except in compliance with the License.
@@ -15,20 +15,16 @@
*/
package net.schmizz.sshj.sftp;
import net.schmizz.concurrent.Promise;
public class Request
public final class Request
extends SFTPPacket<Request> {
private final PacketType type;
private final long reqID;
private final Promise<Response, SFTPException> responsePromise;
public Request(PacketType type, long reqID) {
super(type);
this.type = type;
this.reqID = reqID;
responsePromise = new Promise<Response, SFTPException>("sftp / " + reqID, SFTPException.chainer);
putUInt32(reqID);
}
@@ -40,10 +36,6 @@ public class Request
return type;
}
public Promise<Response, SFTPException> getResponsePromise() {
return responsePromise;
}
@Override
public String toString() {
return "Request{" + reqID + ";" + type + "}";

Some files were not shown because too many files have changed in this diff Show More