| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 | using System.Diagnostics;using System.Threading;using Renci.SshClient.Common;using Renci.SshClient.Messages.Connection;using System.Globalization;namespace Renci.SshClient.Channels{    /// <summary>    /// Implements "forwarded-tcpip" SSH channel.    /// </summary>    internal class ChannelSession : Channel    {        /// <summary>        /// Counts faile channel open attempts        /// </summary>        private int _failedOpenAttempts;        /// <summary>        /// Wait handle to signal when response was received to open the channel        /// </summary>        private EventWaitHandle _channelOpenResponseWaitHandle = new AutoResetEvent(false);        private EventWaitHandle _channelRequestResponse = new ManualResetEvent(false);        private bool _channelRequestSucces;        /// <summary>        /// Gets the type of the channel.        /// </summary>        /// <value>        /// The type of the channel.        /// </value>        public override ChannelTypes ChannelType        {            get { return ChannelTypes.Session; }        }        /// <summary>        /// Opens the channel.        /// </summary>        public virtual void Open()        {            if (!this.IsOpen)            {                //  Try to open channel several times                while (this._failedOpenAttempts < this.ConnectionInfo.RetryAttempts && !this.IsOpen)                {                    this.SendChannelOpenMessage();                    this.WaitHandle(this._channelOpenResponseWaitHandle);                }                if (!this.IsOpen)                {                    throw new SshException(string.Format(CultureInfo.CurrentCulture, "Failed to open a channel after {0} attempts.", this._failedOpenAttempts));                }            }        }        /// <summary>        /// Called when channel is opened by the server.        /// </summary>        /// <param name="remoteChannelNumber">The remote channel number.</param>        /// <param name="initialWindowSize">Initial size of the window.</param>        /// <param name="maximumPacketSize">Maximum size of the packet.</param>        protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize)        {            base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize);            this._channelOpenResponseWaitHandle.Set();        }        /// <summary>        /// Called when channel failed to open.        /// </summary>        /// <param name="reasonCode">The reason code.</param>        /// <param name="description">The description.</param>        /// <param name="language">The language.</param>        protected override void OnOpenFailure(uint reasonCode, string description, string language)        {            this._failedOpenAttempts++;            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Local channel: {0} attempts: {1}.", this.LocalChannelNumber, this._failedOpenAttempts));            this.SessionSemaphore.Release();            this._channelOpenResponseWaitHandle.Set();        }        /// <summary>        /// Called when channel is closed by the server.        /// </summary>        protected override void OnClose()        {            base.OnClose();            //  This timeout needed since when channel is closed it does not immediately becomes available            //  but it takes time for the server to clean up resource and allow new channels to be created.            Thread.Sleep(100);            this.SessionSemaphore.Release();        }        /// <summary>        /// Sends the pseudo terminal request.        /// </summary>        /// <param name="environmentVariable">The environment variable.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="terminalMode">The terminal mode.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, string terminalMode)        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new PseudoTerminalRequestInfo(environmentVariable, columns, rows, width, height, terminalMode)));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the X11 forwarding request.        /// </summary>        /// <param name="isSingleConnection">if set to <c>true</c> the it is single connection.</param>        /// <param name="protocol">The protocol.</param>        /// <param name="cookie">The cookie.</param>        /// <param name="screenNumber">The screen number.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendX11ForwardingRequest(bool isSingleConnection, string protocol, byte[] cookie, uint screenNumber)        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new X11ForwardingRequestInfo(isSingleConnection, protocol, cookie, screenNumber)));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the environment variable request.        /// </summary>        /// <param name="variableName">Name of the variable.</param>        /// <param name="variableValue">The variable value.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendEnvironmentVariableRequest(string variableName, string variableValue)        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new EnvironmentVariableRequestInfo(variableName, variableValue)));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the shell request.        /// </summary>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendShellRequest()        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ShellRequestInfo()));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the exec request.        /// </summary>        /// <param name="command">The command.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendExecRequest(string command)        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExecRequestInfo(command)));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the subsystem request.        /// </summary>        /// <param name="subsystem">The subsystem.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendSubsystemRequest(string subsystem)        {            this._channelRequestResponse.Reset();            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new SubsystemRequestInfo(subsystem)));            this._channelRequestResponse.WaitOne();            return this._channelRequestSucces;        }        /// <summary>        /// Sends the window change request.        /// </summary>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendWindowChangeRequest(uint columns, uint rows, uint width, uint height)        {            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new WindowChangeRequestInfo(columns, rows, width, height)));            return true;        }        /// <summary>        /// Sends the local flow request.        /// </summary>        /// <param name="clientCanDo">if set to <c>true</c> [client can do].</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendLocalFlowRequest(bool clientCanDo)        {            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new XonXoffRequestInfo(clientCanDo)));            return true;        }        /// <summary>        /// Sends the signal request.        /// </summary>        /// <param name="signalName">Name of the signal.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendSignalRequest(string signalName)        {            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new SignalRequestInfo(signalName)));            return true;        }        /// <summary>        /// Sends the exit status request.        /// </summary>        /// <param name="exitStatus">The exit status.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendExitStatusRequest(uint exitStatus)        {            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExitStatusRequestInfo(exitStatus)));            return true;        }        /// <summary>        /// Sends the exit signal request.        /// </summary>        /// <param name="signalName">Name of the signal.</param>        /// <param name="coreDumped">if set to <c>true</c> [core dumped].</param>        /// <param name="errorMessage">The error message.</param>        /// <param name="language">The language.</param>        /// <returns>true if request was successful; otherwise false.</returns>        public bool SendExitSignalRequest(string signalName, bool coreDumped, string errorMessage, string language)        {            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExitSignalRequestInfo(signalName, coreDumped, errorMessage, language)));            return true;        }        /// <summary>        /// Called when channel request was successful        /// </summary>        protected override void OnSuccess()        {            base.OnSuccess();            this._channelRequestSucces = true;            this._channelRequestResponse.Set();        }        /// <summary>        /// Called when channel request failed.        /// </summary>        protected override void OnFailure()        {            base.OnFailure();            this._channelRequestSucces = false;            this._channelRequestResponse.Set();        }        /// <summary>        /// Sends the channel open message.        /// </summary>        protected void SendChannelOpenMessage()        {            lock (this.SessionSemaphore)            {                //  Ensure that channels are available                this.SessionSemaphore.Wait();                this.SendMessage(new ChannelOpenMessage(this.LocalChannelNumber, this.LocalWindowSize, this.PacketSize, new SessionChannelOpenInfo()));            }        }        /// <summary>        /// Releases unmanaged and - optionally - managed resources        /// </summary>        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>        protected override void Dispose(bool disposing)        {            if (this._channelOpenResponseWaitHandle != null)            {                this._channelOpenResponseWaitHandle.Dispose();                this._channelOpenResponseWaitHandle = null;            }            if (this._channelRequestResponse != null)            {                this._channelRequestResponse.Dispose();                this._channelRequestResponse = null;            }            base.Dispose(disposing);        }    }}
 |