Skip to content
Closed
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
8 changes: 4 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.15.3" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.4" />
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.6.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.220" />
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.222" />
<!-- Should stay on LTS .NET releases. -->
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.9" />
<PackageVersion Include="MSTest" Version="3.9.3" />
<PackageVersion Include="MSTest" Version="3.11.0" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.7.115" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.8.118" />
<PackageVersion Include="PolySharp" Version="1.15.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.15.0.120848" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
Expand Down
28 changes: 0 additions & 28 deletions src/Renci.SshNet/Abstractions/SocketAbstraction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,6 @@ namespace Renci.SshNet.Abstractions
{
internal static partial class SocketAbstraction
{
public static bool CanRead(Socket socket)
{
if (socket.Connected)
{
return socket.Poll(-1, SelectMode.SelectRead) && socket.Available > 0;
}

return false;
}

/// <summary>
/// Returns a value indicating whether the specified <see cref="Socket"/> can be used
/// to send data.
/// </summary>
/// <param name="socket">The <see cref="Socket"/> to check.</param>
/// <returns>
/// <see langword="true"/> if <paramref name="socket"/> can be written to; otherwise, <see langword="false"/>.
/// </returns>
public static bool CanWrite(Socket socket)
{
if (socket != null && socket.Connected)
{
return socket.Poll(-1, SelectMode.SelectWrite);
}

return false;
}

public static Socket Connect(IPEndPoint remoteEndpoint, TimeSpan connectTimeout)
{
var socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
Expand Down
35 changes: 24 additions & 11 deletions src/Renci.SshNet/Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
using System.Globalization;
#if !NET
using System.IO;
using System.Threading.Tasks;
#endif
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading;

using Renci.SshNet.Abstractions;
using Renci.SshNet.Messages;

namespace Renci.SshNet.Common
Expand Down Expand Up @@ -319,16 +319,6 @@ public static byte[] Concat(this byte[] first, byte[] second)
return concat;
}

internal static bool CanRead(this Socket socket)
{
return SocketAbstraction.CanRead(socket);
}

internal static bool CanWrite(this Socket socket)
{
return SocketAbstraction.CanWrite(socket);
}

internal static bool IsConnected(this Socket socket)
{
if (socket is null)
Expand Down Expand Up @@ -409,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
Loading
Loading