|
|
@@ -1,6 +1,6 @@
|
|
|
using System;
|
|
|
-using System.IO;
|
|
|
|
|
|
+using Renci.SshNet.Messages.Authentication;
|
|
|
using Renci.SshNet.Security;
|
|
|
|
|
|
namespace Renci.SshNet.Compression
|
|
|
@@ -10,35 +10,23 @@ namespace Renci.SshNet.Compression
|
|
|
/// </summary>
|
|
|
public abstract class Compressor : Algorithm, IDisposable
|
|
|
{
|
|
|
- private readonly ZlibStream _compressor;
|
|
|
- private readonly ZlibStream _decompressor;
|
|
|
- private MemoryStream _compressorStream;
|
|
|
- private MemoryStream _decompressorStream;
|
|
|
- private bool _isDisposed;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets or sets a value indicating whether compression is active.
|
|
|
- /// </summary>
|
|
|
- /// <value>
|
|
|
- /// <see langword="true"/> if compression is active; otherwise, <see langword="false"/>.
|
|
|
- /// </value>
|
|
|
- protected bool IsActive { get; set; }
|
|
|
+ private readonly bool _delayedCompression;
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Gets the session.
|
|
|
- /// </summary>
|
|
|
- protected Session Session { get; private set; }
|
|
|
+ private bool _isActive;
|
|
|
+ private Session _session;
|
|
|
+ private bool _isDisposed;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Initializes a new instance of the <see cref="Compressor"/> class.
|
|
|
/// </summary>
|
|
|
- protected Compressor()
|
|
|
+ /// <param name="delayedCompression">
|
|
|
+ /// <see langword="false"/> to start compression after receiving SSH_MSG_NEWKEYS.
|
|
|
+ /// <see langword="true"/> to delay compression util receiving SSH_MSG_USERAUTH_SUCCESS.
|
|
|
+ /// <see href="https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt"/>.
|
|
|
+ /// </param>
|
|
|
+ protected Compressor(bool delayedCompression)
|
|
|
{
|
|
|
- _compressorStream = new MemoryStream();
|
|
|
- _decompressorStream = new MemoryStream();
|
|
|
-
|
|
|
- _compressor = new ZlibStream(_compressorStream, CompressionMode.Compress);
|
|
|
- _decompressor = new ZlibStream(_decompressorStream, CompressionMode.Decompress);
|
|
|
+ _delayedCompression = delayedCompression;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -47,7 +35,15 @@ namespace Renci.SshNet.Compression
|
|
|
/// <param name="session">The session.</param>
|
|
|
public virtual void Init(Session session)
|
|
|
{
|
|
|
- Session = session;
|
|
|
+ if (_delayedCompression)
|
|
|
+ {
|
|
|
+ _session = session;
|
|
|
+ _session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _isActive = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -57,7 +53,7 @@ namespace Renci.SshNet.Compression
|
|
|
/// <returns>
|
|
|
/// The compressed data.
|
|
|
/// </returns>
|
|
|
- public virtual byte[] Compress(byte[] data)
|
|
|
+ public byte[] Compress(byte[] data)
|
|
|
{
|
|
|
return Compress(data, 0, data.Length);
|
|
|
}
|
|
|
@@ -73,7 +69,7 @@ namespace Renci.SshNet.Compression
|
|
|
/// </returns>
|
|
|
public virtual byte[] Compress(byte[] data, int offset, int length)
|
|
|
{
|
|
|
- if (!IsActive)
|
|
|
+ if (!_isActive)
|
|
|
{
|
|
|
if (offset == 0 && length == data.Length)
|
|
|
{
|
|
|
@@ -85,13 +81,20 @@ namespace Renci.SshNet.Compression
|
|
|
return buffer;
|
|
|
}
|
|
|
|
|
|
- _compressorStream.SetLength(0);
|
|
|
-
|
|
|
- _compressor.Write(data, offset, length);
|
|
|
-
|
|
|
- return _compressorStream.ToArray();
|
|
|
+ return CompressCore(data, offset, length);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Compresses the specified data.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="data">Data to compress.</param>
|
|
|
+ /// <param name="offset">The zero-based byte offset in <paramref name="data"/> at which to begin reading the data to compress. </param>
|
|
|
+ /// <param name="length">The number of bytes to be compressed. </param>
|
|
|
+ /// <returns>
|
|
|
+ /// The compressed data.
|
|
|
+ /// </returns>
|
|
|
+ protected abstract byte[] CompressCore(byte[] data, int offset, int length);
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Decompresses the specified data.
|
|
|
/// </summary>
|
|
|
@@ -99,7 +102,7 @@ namespace Renci.SshNet.Compression
|
|
|
/// <returns>
|
|
|
/// The decompressed data.
|
|
|
/// </returns>
|
|
|
- public virtual byte[] Decompress(byte[] data)
|
|
|
+ public byte[] Decompress(byte[] data)
|
|
|
{
|
|
|
return Decompress(data, 0, data.Length);
|
|
|
}
|
|
|
@@ -115,7 +118,7 @@ namespace Renci.SshNet.Compression
|
|
|
/// </returns>
|
|
|
public virtual byte[] Decompress(byte[] data, int offset, int length)
|
|
|
{
|
|
|
- if (!IsActive)
|
|
|
+ if (!_isActive)
|
|
|
{
|
|
|
if (offset == 0 && length == data.Length)
|
|
|
{
|
|
|
@@ -127,11 +130,24 @@ namespace Renci.SshNet.Compression
|
|
|
return buffer;
|
|
|
}
|
|
|
|
|
|
- _decompressorStream.SetLength(0);
|
|
|
+ return DecompressCore(data, offset, length);
|
|
|
+ }
|
|
|
|
|
|
- _decompressor.Write(data, offset, length);
|
|
|
+ /// <summary>
|
|
|
+ /// Decompresses the specified data.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="data">Compressed data.</param>
|
|
|
+ /// <param name="offset">The zero-based byte offset in <paramref name="data"/> at which to begin reading the data to decompress. </param>
|
|
|
+ /// <param name="length">The number of bytes to be read from the compressed data. </param>
|
|
|
+ /// <returns>
|
|
|
+ /// The decompressed data.
|
|
|
+ /// </returns>
|
|
|
+ protected abstract byte[] DecompressCore(byte[] data, int offset, int length);
|
|
|
|
|
|
- return _decompressorStream.ToArray();
|
|
|
+ private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs<SuccessMessage> e)
|
|
|
+ {
|
|
|
+ _isActive = true;
|
|
|
+ _session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -156,20 +172,6 @@ namespace Renci.SshNet.Compression
|
|
|
|
|
|
if (disposing)
|
|
|
{
|
|
|
- var compressorStream = _compressorStream;
|
|
|
- if (compressorStream != null)
|
|
|
- {
|
|
|
- compressorStream.Dispose();
|
|
|
- _compressorStream = null;
|
|
|
- }
|
|
|
-
|
|
|
- var decompressorStream = _decompressorStream;
|
|
|
- if (decompressorStream != null)
|
|
|
- {
|
|
|
- decompressorStream.Dispose();
|
|
|
- _decompressorStream = null;
|
|
|
- }
|
|
|
-
|
|
|
_isDisposed = true;
|
|
|
}
|
|
|
}
|