diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index 25975872d..8ab9736d8 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.Net.Sockets; using System.Threading; @@ -715,8 +714,14 @@ private void OnChannelRequest(object sender, MessageEventArgs uint LocalPacketSize { get; } + /// + /// Gets the remote channel number. + /// + uint RemoteChannelNumber { get; } + /// /// Gets the maximum size of a data packet that can be sent using the channel. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/UnknownRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/UnknownRequestInfo.cs new file mode 100644 index 000000000..6cd19b5a6 --- /dev/null +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/UnknownRequestInfo.cs @@ -0,0 +1,22 @@ +namespace Renci.SshNet.Messages.Connection +{ + /// + /// Represents an unknown request information that we can't handle. + /// + internal sealed class UnknownRequestInfo : RequestInfo + { + /// + /// Gets the name of the request. + /// + public override string RequestName { get; } + + /// + /// Initializes a new instance of the class. + /// The name of the unknown request. + /// + internal UnknownRequestInfo(string requestName) + { + RequestName = requestName; + } + } +} diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 647b041bd..df61cda7e 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -464,7 +464,7 @@ private void Channel_RequestReceived(object sender, ChannelRequestEventArgs e) if (exitStatusInfo.WantReply) { - var replyMessage = new ChannelSuccessMessage(_channel.LocalChannelNumber); + var replyMessage = new ChannelSuccessMessage(_channel.RemoteChannelNumber); _session.SendMessage(replyMessage); } } @@ -472,7 +472,7 @@ private void Channel_RequestReceived(object sender, ChannelRequestEventArgs e) { if (e.Info.WantReply) { - var replyMessage = new ChannelFailureMessage(_channel.LocalChannelNumber); + var replyMessage = new ChannelFailureMessage(_channel.RemoteChannelNumber); _session.SendMessage(replyMessage); } } diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_HandleUnknownMessage.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_HandleUnknownMessage.cs new file mode 100644 index 000000000..426b2463a --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_HandleUnknownMessage.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Connection; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + [TestClass] + public class ChannelTest_OnSessionChannelRequestReceived_HandleUnknownMessage : ChannelTestBase + { + private uint _localWindowSize; + private uint _localPacketSize; + private uint _localChannelNumber; + private uint _remoteChannelNumber; + private uint _remoteWindowSize; + private uint _remotePacketSize; + private ChannelStub _channel; + private IList _channelExceptionRegister; + private UnknownRequestInfoWithWantReply _requestInfo; + + protected override void SetupData() + { + var random = new Random(); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); + _localPacketSize = _localWindowSize - 1; + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelExceptionRegister = new List(); + _requestInfo = new UnknownRequestInfoWithWantReply(); + } + + protected override void SetupMocks() + { + _ = SessionMock.Setup(p => p.ConnectionInfo) + .Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password"))); + _ = SessionMock.Setup(p => p.SendMessage(It.IsAny())); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); + _channel.SetIsOpen(true); + _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); + } + + protected override void Act() + { + SessionMock.Raise(s => s.ChannelRequestReceived += null, + new MessageEventArgs(new ChannelRequestMessage(_localChannelNumber, _requestInfo))); + } + + [TestMethod] + public void FailureMessageWasSent() + { + SessionMock.Verify(p => p.SendMessage(It.Is(m => m.LocalChannelNumber == _channel.RemoteChannelNumber)), Times.Once); + } + + [TestMethod] + public void NoExceptionShouldHaveFired() + { + Assert.AreEqual(0, _channelExceptionRegister.Count); + } + } + + internal class UnknownRequestInfoWithWantReply : RequestInfo + { + public override string RequestName + { + get + { + return nameof(UnknownRequestInfoWithWantReply); + } + } + + internal UnknownRequestInfoWithWantReply() + { + WantReply = true; + } + } +} diff --git a/test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs index 1f116f796..e4ec77f37 100644 --- a/test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs +++ b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs @@ -370,6 +370,8 @@ public void Open() public uint LocalPacketSize => throw new NotImplementedException(); + public uint RemoteChannelNumber => throw new NotImplementedException(); + public uint RemotePacketSize => throw new NotImplementedException(); public bool IsOpen => throw new NotImplementedException();