Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 2 additions & 2 deletions src/Renci.SshNet/Abstractions/SocketAbstraction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static void ClearReadBuffer(Socket socket)

public static int ReadPartial(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout)
{
socket.ReceiveTimeout = (int) timeout.TotalMilliseconds;
socket.ReceiveTimeout = timeout.AsTimeout();

try
{
Expand Down Expand Up @@ -274,7 +274,7 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS
var totalBytesRead = 0;
var totalBytesToRead = size;

socket.ReceiveTimeout = (int) readTimeout.TotalMilliseconds;
socket.ReceiveTimeout = readTimeout.AsTimeout();

do
{
Expand Down
2 changes: 2 additions & 0 deletions src/Renci.SshNet/BaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public TimeSpan KeepAliveInterval
{
CheckDisposed();

value.EnsureValidTimeout();

if (value == _keepAliveInterval)
{
return;
Expand Down
54 changes: 54 additions & 0 deletions src/Renci.SshNet/Common/TimeSpanExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
#if NET21_OR_GREATER || NET6_0_OR_GREATER
using System.Runtime.CompilerServices;
#endif

namespace Renci.SshNet.Common
{
/// <summary>
/// Provides extension methods for <see cref="TimeSpan"/>.
/// </summary>
internal static class TimeSpanExtensions
{
/// <summary>
/// Returns the specified <paramref name="timeSpan"/> as a valid timeout in milliseconds.
/// </summary>
/// <param name="timeSpan">The <see cref="TimeSpan"/> to ensure validity.</param>
/// <param name="callerMemberName">The name of the calling member.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when <paramref name="timeSpan"/> does not represent a value between -1 and <see cref="int.MaxValue"/>, inclusive.
/// </exception>
public static int AsTimeout(this TimeSpan timeSpan,
#if NET21_OR_GREATER || NET6_0_OR_GREATER
[CallerArgumentExpression(nameof(timeSpan))]
#endif
string callerMemberName = "")
{
var timeoutInMilliseconds = timeSpan.TotalMilliseconds;
return timeoutInMilliseconds is < -1d or > int.MaxValue
? throw new ArgumentOutOfRangeException(callerMemberName, "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.")
: (int) timeoutInMilliseconds;
}

/// <summary>
/// Ensures that the specified <paramref name="timeSpan"/> represents a valid timeout in milliseconds.
/// </summary>
/// <param name="timeSpan">The <see cref="TimeSpan"/> to ensure validity.</param>
/// <param name="callerMemberName">The name of the calling member.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when <paramref name="timeSpan"/> does not represent a value between -1 and <see cref="int.MaxValue"/>, inclusive.
/// </exception>
public static void EnsureValidTimeout(this TimeSpan timeSpan,
#if NET21_OR_GREATER || NET6_0_OR_GREATER
[CallerArgumentExpression(nameof(timeSpan))]
#endif
string callerMemberName = "")
{
var timeoutInMilliseconds = timeSpan.TotalMilliseconds;
if (timeoutInMilliseconds is < -1d or > int.MaxValue)
{
throw new ArgumentOutOfRangeException(callerMemberName, "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
}
}
}
}
30 changes: 28 additions & 2 deletions src/Renci.SshNet/ConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public class ConnectionInfo : IConnectionInfoInternal
/// 1 second.
/// </value>
private static readonly TimeSpan DefaultChannelCloseTimeout = TimeSpan.FromSeconds(1);
private TimeSpan _timeout;
private TimeSpan _channelCloseTimeout;

/// <summary>
/// Gets supported key exchange algorithms for this connection.
Expand Down Expand Up @@ -145,7 +147,19 @@ public class ConnectionInfo : IConnectionInfoInternal
/// <value>
/// The connection timeout. The default value is 30 seconds.
/// </value>
public TimeSpan Timeout { get; set; }
public TimeSpan Timeout
{
get
{
return _timeout;
}
set
{
value.EnsureValidTimeout();

_timeout = value;
}
}

/// <summary>
/// Gets or sets the timeout to use when waiting for a server to acknowledge closing a channel.
Expand All @@ -157,7 +171,19 @@ public class ConnectionInfo : IConnectionInfoInternal
/// If a server does not send a <c>SSH_MSG_CHANNEL_CLOSE</c> message before the specified timeout
/// elapses, the channel will be closed immediately.
/// </remarks>
public TimeSpan ChannelCloseTimeout { get; set; }
public TimeSpan ChannelCloseTimeout
{
get
{
return _channelCloseTimeout;
}
set
{
value.EnsureValidTimeout();

_channelCloseTimeout = value;
}
}

/// <summary>
/// Gets or sets the character encoding.
Expand Down
2 changes: 2 additions & 0 deletions src/Renci.SshNet/ForwardedPort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ public void Dispose()
/// <param name="timeout">The maximum amount of time to wait for pending requests to finish processing.</param>
protected virtual void StopPort(TimeSpan timeout)
{
timeout.EnsureValidTimeout();

RaiseClosing();

var session = Session;
Expand Down
2 changes: 2 additions & 0 deletions src/Renci.SshNet/ForwardedPortDynamic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ protected override void StartPort()
/// <param name="timeout">The maximum amount of time to wait for pending requests to finish processing.</param>
protected override void StopPort(TimeSpan timeout)
{
timeout.EnsureValidTimeout();

if (!ForwardedPortStatus.ToStopping(ref _status))
{
return;
Expand Down
2 changes: 2 additions & 0 deletions src/Renci.SshNet/ForwardedPortLocal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ protected override void StartPort()
/// <param name="timeout">The maximum amount of time to wait for pending requests to finish processing.</param>
protected override void StopPort(TimeSpan timeout)
{
timeout.EnsureValidTimeout();

if (!ForwardedPortStatus.ToStopping(ref _status))
{
return;
Expand Down
2 changes: 2 additions & 0 deletions src/Renci.SshNet/ForwardedPortRemote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ protected override void StartPort()
/// <param name="timeout">The maximum amount of time to wait for the port to stop.</param>
protected override void StopPort(TimeSpan timeout)
{
timeout.EnsureValidTimeout();

if (!ForwardedPortStatus.ToStopping(ref _status))
{
return;
Expand Down
8 changes: 1 addition & 7 deletions src/Renci.SshNet/NetConfClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ public TimeSpan OperationTimeout
}
set
{
var timeoutInMilliseconds = value.TotalMilliseconds;
if (timeoutInMilliseconds is < -1d or > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(value), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
}

_operationTimeout = (int) timeoutInMilliseconds;
_operationTimeout = value.AsTimeout();
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/Renci.SshNet/ScpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public partial class ScpClient : BaseClient
private static readonly Regex TimestampRe = new Regex(@"T(?<mtime>\d+) 0 (?<atime>\d+) 0", RegexOptions.Compiled);

private IRemotePathTransformation _remotePathTransformation;
private TimeSpan _operationTimeout;

/// <summary>
/// Gets or sets the operation timeout.
Expand All @@ -46,7 +47,19 @@ public partial class ScpClient : BaseClient
/// The timeout to wait until an operation completes. The default value is negative
/// one (-1) milliseconds, which indicates an infinite time-out period.
/// </value>
public TimeSpan OperationTimeout { get; set; }
public TimeSpan OperationTimeout
{
get
{
return _operationTimeout;
}
set
{
value.EnsureValidTimeout();

_operationTimeout = value;
}
}

/// <summary>
/// Gets or sets the size of the buffer.
Expand Down
15 changes: 14 additions & 1 deletion src/Renci.SshNet/Sftp/SftpFileStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class SftpFileStream : Stream
private bool _canRead;
private bool _canSeek;
private bool _canWrite;
private TimeSpan _timeout;

/// <summary>
/// Gets a value indicating whether the current stream supports reading.
Expand Down Expand Up @@ -176,7 +177,19 @@ public virtual byte[] Handle
/// <value>
/// The timeout.
/// </value>
public TimeSpan Timeout { get; set; }
public TimeSpan Timeout
{
get
{
return _timeout;
}
set
{
_timeout.EnsureValidTimeout();

_timeout = value;
}
}

private SftpFileStream(ISftpSession session, string path, FileAccess access, int bufferSize, byte[] handle, long position)
{
Expand Down
8 changes: 1 addition & 7 deletions src/Renci.SshNet/SftpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,7 @@ public TimeSpan OperationTimeout
{
CheckDisposed();

var timeoutInMilliseconds = value.TotalMilliseconds;
if (timeoutInMilliseconds is < -1d or > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(value), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
}

_operationTimeout = (int) timeoutInMilliseconds;
_operationTimeout = value.AsTimeout();
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/Renci.SshNet/SshCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class SshCommand : IDisposable
private bool _hasError;
private bool _isDisposed;
private ChannelInputStream _inputStream;
private TimeSpan _commandTimeout;

/// <summary>
/// Gets the command text.
Expand All @@ -44,7 +45,19 @@ public class SshCommand : IDisposable
/// <value>
/// The command timeout.
/// </value>
public TimeSpan CommandTimeout { get; set; }
public TimeSpan CommandTimeout
{
get
{
return _commandTimeout;
}
set
{
_commandTimeout.EnsureValidTimeout();

_commandTimeout = value;
}
}

/// <summary>
/// Gets the command exit status.
Expand Down
4 changes: 4 additions & 0 deletions test/Renci.SshNet.Tests/Classes/NetConfClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ public void OperationTimeout_LessThanLowerLimit()
{
Assert.IsNull(ex.InnerException);
ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex);
#if NET21_OR_GREATER || NET6_0_OR_GREATER
Assert.AreEqual("value", ex.ParamName);
#endif
}
}

Expand All @@ -105,7 +107,9 @@ public void OperationTimeout_GreaterThanLowerLimit()
{
Assert.IsNull(ex.InnerException);
ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex);
#if NET21_OR_GREATER || NET6_0_OR_GREATER
Assert.AreEqual("value", ex.ParamName);
#endif
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions test/Renci.SshNet.Tests/Classes/SftpClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ public void OperationTimeout_LessThanLowerLimit()
{
Assert.IsNull(ex.InnerException);
ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex);
#if NET21_OR_GREATER || NET6_0_OR_GREATER
Assert.AreEqual("value", ex.ParamName);
#endif
}
}

Expand All @@ -108,7 +110,9 @@ public void OperationTimeout_GreaterThanLowerLimit()
{
Assert.IsNull(ex.InnerException);
ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex);
#if NET21_OR_GREATER || NET6_0_OR_GREATER
Assert.AreEqual("value", ex.ParamName);
#endif
}
}

Expand Down