Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Renci.SshNet/Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Globalization;
#if !NET
using System.IO;
using System.Threading.Tasks;
#endif
using System.Net;
using System.Net.Sockets;
Expand Down Expand Up @@ -398,6 +399,29 @@ internal static void ReadExactly(this Stream stream, byte[] buffer, int offset,
totalRead += read;
}
}

internal static Task<T> WaitAsync<T>(this Task<T> task, CancellationToken cancellationToken)
{
if (task.IsCompleted || !cancellationToken.CanBeCanceled)
{
return task;
}

return WaitCore();

async Task<T> WaitCore()
{
TaskCompletionSource<T> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);

using var reg = cancellationToken.Register(
() => tcs.TrySetCanceled(cancellationToken),
useSynchronizationContext: false);

var completedTask = await Task.WhenAny(task, tcs.Task).ConfigureAwait(false);

return await completedTask.ConfigureAwait(false);
}
}
#endif
}
}
12 changes: 0 additions & 12 deletions src/Renci.SshNet/IServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,6 @@ internal partial interface IServiceFactory
/// <exception cref="SshConnectionException">No key exchange algorithm is supported by both client and server.</exception>
IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> clientAlgorithms, string[] serverAlgorithms);

/// <summary>
/// Creates an <see cref="ISftpFileReader"/> for the specified file and with the specified
/// buffer size.
/// </summary>
/// <param name="fileName">The file to read.</param>
/// <param name="sftpSession">The SFTP session to use.</param>
/// <param name="bufferSize">The size of buffer.</param>
/// <returns>
/// An <see cref="ISftpFileReader"/>.
/// </returns>
ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize);

/// <summary>
/// Creates a new <see cref="ISftpResponseFactory"/> instance.
/// </summary>
Expand Down
47 changes: 0 additions & 47 deletions src/Renci.SshNet/ServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
using System.Net.Sockets;
using System.Text;

using Microsoft.Extensions.Logging;

using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages.Transport;
Expand Down Expand Up @@ -118,51 +116,6 @@ public INetConfSession CreateNetConfSession(ISession session, int operationTimeo
return new NetConfSession(session, operationTimeout);
}

/// <summary>
/// Creates an <see cref="ISftpFileReader"/> for the specified file and with the specified
/// buffer size.
/// </summary>
/// <param name="fileName">The file to read.</param>
/// <param name="sftpSession">The SFTP session to use.</param>
/// <param name="bufferSize">The size of buffer.</param>
/// <returns>
/// An <see cref="ISftpFileReader"/>.
/// </returns>
public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize)
{
const int defaultMaxPendingReads = 10;

// Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this
// causes a performance degradation on Sun SSH
var openAsyncResult = sftpSession.BeginOpen(fileName, Flags.Read, callback: null, state: null);
var handle = sftpSession.EndOpen(openAsyncResult);

var statAsyncResult = sftpSession.BeginLStat(fileName, callback: null, state: null);

long? fileSize;
int maxPendingReads;

var chunkSize = sftpSession.CalculateOptimalReadLength(bufferSize);

// fallback to a default maximum of pending reads when remote server does not allow us to obtain
// the attributes of the file
try
{
var fileAttributes = sftpSession.EndLStat(statAsyncResult);
fileSize = fileAttributes.Size;
maxPendingReads = Math.Min(100, (int)Math.Ceiling((double)fileAttributes.Size / chunkSize) + 1);
}
catch (SshException ex)
{
fileSize = null;
maxPendingReads = defaultMaxPendingReads;

sftpSession.SessionLoggerFactory.CreateLogger<ServiceFactory>().LogInformation(ex, "Failed to obtain size of file. Allowing maximum {MaxPendingReads} pending reads", maxPendingReads);
}

return sftpSession.CreateFileReader(handle, sftpSession, chunkSize, maxPendingReads, fileSize);
}

/// <summary>
/// Creates a new <see cref="ISftpResponseFactory"/> instance.
/// </summary>
Expand Down
23 changes: 0 additions & 23 deletions src/Renci.SshNet/Sftp/ISftpFileReader.cs

This file was deleted.

17 changes: 1 addition & 16 deletions src/Renci.SshNet/Sftp/ISftpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,10 @@ internal interface ISftpSession : ISubsystemSession
/// Asynchronously performs a <c>SSH_FXP_FSTAT</c> request.
/// </summary>
/// <param name="handle">The handle.</param>
/// <param name="nullOnError">If set to <see langword="true"/>, <see langword="null"/> is returned in case of an error.</param>
/// <returns>
/// The file attributes.
/// </returns>
SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError);
SftpFileAttributes RequestFStat(byte[] handle);

/// <summary>
/// Asynchronously performs a <c>SSH_FXP_FSTAT</c> request.
Expand Down Expand Up @@ -522,19 +521,5 @@ void RequestWrite(byte[] handle,
/// Currently, we do not take the remote window size into account.
/// </remarks>
uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle);

/// <summary>
/// Creates an <see cref="ISftpFileReader"/> for reading the content of the file represented by a given <paramref name="handle"/>.
/// </summary>
/// <param name="handle">The handle of the file to read.</param>
/// <param name="sftpSession">The SFTP session.</param>
/// <param name="chunkSize">The maximum number of bytes to read with each chunk.</param>
/// <param name="maxPendingReads">The maximum number of pending reads.</param>
/// <param name="fileSize">The size of the file or <see langword="null"/> when the size could not be determined.</param>
/// <returns>
/// An <see cref="ISftpFileReader"/> for reading the content of the file represented by the
/// specified <paramref name="handle"/>.
/// </returns>
ISftpFileReader CreateFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, int maxPendingReads, long? fileSize);
}
}
Loading