Exemple #1
0
        public static Task <string> ExpectOnceAsync(this ShellStream Self, Regex Expect, CancellationToken Token = default)
        {
            Token.ThrowIfCancellationRequested();
            var          Task       = new TaskCompletionSource <string>();
            IDisposable  Disposable = null;
            IAsyncResult result     = null;

            Disposable = Token.Register(async() => {
                try {
                    if (result != null)
                    {
                        var _result = result;
                        result      = null;
                        var expect  = await System.Threading.Tasks.Task.Run(() => Self.EndExpect(_result));
                    }
                } catch { }
                Task.TrySetCanceled(Token);
            });
            result = Self.BeginExpect(async ar => {
                try {
                    if (result != null)
                    {
                        result     = null;
                        var expect = await System.Threading.Tasks.Task.Run(() => Self.EndExpect(ar));
                        Task.TrySetResult(expect);
                    }
                } catch (Exception e) {
                    Task.TrySetException(e);
                } finally {
                    Disposable?.Dispose();
                    Disposable = null;
                }
            }, new ExpectAction(Expect, async v => {
                try {
                    if (result != null)
                    {
                        var _result = result;
                        result      = null;
                        var expect  = await System.Threading.Tasks.Task.Run(() => Self.EndExpect(_result));
                        Task.TrySetResult(expect);
                    }
                } catch (Exception e) {
                    Task.TrySetException(e);
                } finally {
                    Disposable?.Dispose();
                    Disposable = null;
                }
            }));
            return(Task.Task);
        }
Exemple #2
0
 public void BeginExpectTest1()
 {
     Session session = null; // TODO: Initialize to an appropriate value
     string terminalName = string.Empty; // TODO: Initialize to an appropriate value
     uint columns = 0; // TODO: Initialize to an appropriate value
     uint rows = 0; // TODO: Initialize to an appropriate value
     uint width = 0; // TODO: Initialize to an appropriate value
     uint height = 0; // TODO: Initialize to an appropriate value
     int maxLines = 0; // TODO: Initialize to an appropriate value
     IDictionary<TerminalModes, uint> terminalModeValues = null; // TODO: Initialize to an appropriate value
     ShellStream target = new ShellStream(session, terminalName, columns, rows, width, height, maxLines, terminalModeValues); // TODO: Initialize to an appropriate value
     ExpectAction[] expectActions = null; // TODO: Initialize to an appropriate value
     IAsyncResult expected = null; // TODO: Initialize to an appropriate value
     IAsyncResult actual;
     actual = target.BeginExpect(expectActions);
     Assert.AreEqual(expected, actual);
     Assert.Inconclusive("Verify the correctness of this test method.");
 }
        public override bool ExecuteAsUser(string command, string arguments, out ProcessExecuteStatus process_status, out string process_output, out string process_error, string user, SecureString password, Action <string> OutputDataReceived = null, Action <string> OutputErrorReceived = null, [CallerMemberName] string memberName = "", [CallerFilePath] string fileName = "", [CallerLineNumber] int lineNumber = 0)
        {
            CallerInformation caller = new CallerInformation(memberName, fileName, lineNumber);

            if (!this.IsConnected)
            {
                throw new InvalidOperationException("The SSH session is not connected.");
            }
            process_status = ProcessExecuteStatus.Unknown;
            process_output = "";
            process_error  = "";
            string c;

            if (password == null)
            {
                c = string.Format("-n -u {0} -s {1} {2}", user, command, arguments);
                return(this.Execute("sudo", c, out process_status, out process_output, out process_error));
            }
            StringBuilder shell_data = new StringBuilder();
            ShellStream   stream     = this.SshClient.CreateShellStream("dumb", 0, 0, 800, 600, 1024, new Dictionary <TerminalModes, uint> {
                { TerminalModes.ECHO, 0 }
            });

            stream.DataReceived += (s, d) => shell_data.Append(Encoding.UTF8.GetString(d.Data));
            c = string.Format("PAGER=cat su -c \"echo CMD_START && {0} {1} && echo CMD_SUCCESS || echo CMD_ERROR\" {2} || echo CMD_ERROR", command, arguments, user);
            byte[]    b  = Encoding.UTF8.GetBytes(c + this.LineTerminator);
            Stopwatch cs = new Stopwatch();

            cs.Start();
            IAsyncResult wr = stream.BeginWrite(b, 0, b.Length, new AsyncCallback(SshStreamWriteAsyncCallback), new KeyValuePair <string, ShellStream>(c, stream));

            stream.EndWrite(wr);
            bool got_password_prompt = false;

            ExpectAction[] got_password_prompt_action =
            {
                new ExpectAction("Password:"******"Unexpected response from server attempting to execute {0}: {1}", c, shell_data);
                return(false);
            }
            stream.EndWrite(wr);
            bool   cmd_success = false;
            string cmd_output  = string.Empty;

            ExpectAction[] cmd_actions =
            {
                new ExpectAction("CMD_ERROR",   (o) =>
                {
                    cmd_output  = o.Replace("CMD_ERROR", string.Empty);
                    cmd_success = false;
                }),
                new ExpectAction("CMD_SUCCESS", (o) =>
                {
                    cmd_output  = o.Replace("CMD_SUCCESS", string.Empty).Replace("CMD_START", string.Empty);
                    cmd_success = true;
                }),
            };
            er = stream.BeginExpect(new TimeSpan(0, 0, 5), new AsyncCallback(SshExpectAsyncCallback), new KeyValuePair <string, Stopwatch>(c, cs), cmd_actions);
            stream.EndExpect(er);
            if (!cmd_success)
            {
                process_status = ProcessExecuteStatus.Error;
                Debug(caller, "Execute {0} {1} returned non-zero exit code. Output: {2}.", command, arguments, cmd_output);
                return(false);
            }
            else
            {
                Debug(caller, "Execute {0} {1} returned zero exit code. Output: {2}.", command, arguments, cmd_output);
                process_status = ProcessExecuteStatus.Completed;
                process_output = cmd_output.Trim('\r', '\n');
                return(true);
            }
        }
Exemple #4
0
        /// <summary>
        /// Dump the input until we see a particular string in the returning text.
        /// </summary>
        /// <param name="s">The ssh stream to run against</param>
        /// <param name="matchText">The text to match - command is done and we return when we see it</param>
        /// <param name="failNow">Function that returns true if we should throw out right away</param>
        /// <param name="ongo">When we see a complete line, call this function. Defaults to null</param>
        /// <param name="secondsTimeout">How long should there be before we have a timeout.</param>
        /// <param name="refreshTimeout">If we see something back from the host, reset the timeout counter</param>
        /// <param name="crlfExpectedAtEnd">If the crlf is expected, then eat it when we see it. A command line prompt, for example, will not have this.</param>
        /// <param name="seeAndRespond">Dictionary of strings to look for and to respond to with further input.</param>
        private static async Task DumpTillFind(ShellStream s,
                                               SshClient client,
                                               string matchText,
                                               Action <string> ongo   = null,
                                               int secondsTimeout     = 60 *60,
                                               bool refreshTimeout    = false,
                                               Func <bool> failNow    = null,
                                               bool crlfExpectedAtEnd = false,
                                               Dictionary <string, string> seeAndRespond = null
                                               )
        {
            /// <summary>
            /// How long to go before checking for update data from the stream. The actual timeout accuracy
            /// when refreshtimeout is set will depend on this.
            /// </summary>
            TimeSpan TimeoutGranularity = TimeSpan.FromSeconds(5);

            // Send back text we see if there is someone watching.
            // Don't send back the matched text.
            var lb = new LineBuffer();

            if (ongo != null)
            {
                lb.AddAction(l => { if (!l.Contains(matchText))
                                    {
                                        ongo(l);
                                    }
                             });
            }

            // Set when we see the text we are trying to match.
            bool gotmatch = false;

            // The Shell Stream works by looking for strings, and when it matches, performing a call out and returning.
            // The most obvious string to wait for is our matched string.
            var expectedMatchText = matchText + (crlfExpectedAtEnd ? LineBuffer.CrLf : "");
            var matchText_action  = new ExpectAction(expectedMatchText, l =>
            {
                Trace.WriteLine($"DumpTillFill: Found expected Text: '{SummarizeText(l)}'");
                lb.Add(l);
                gotmatch = true;
            });

            Trace.WriteLine($"DumpTillFind: searching for text: {matchText} (with crlf: {crlfExpectedAtEnd})");

            // Next is the end-of-line action.
            var matchEOL_action = new ExpectAction(new Regex("^.*" + LineBuffer.CrLf + "$"), l => {
                if (!gotmatch)
                {
                    lb.Add(l);
                }
            });

            // Finally, there are some see-and-then-send actions that might be present. When we see a match, send back some text.
            // This is an easy way to deal with a conversation (like a password request).
            var seeAndRespond_actions = seeAndRespond == null
                        ? Enumerable.Empty <ExpectAction>()
                        : seeAndRespond
                                        .Select(sr => new ExpectAction(sr.Key, whatMatched =>
            {
                Trace.WriteLine($"DumpTillFill: Found seeAndRespond: {whatMatched}");
                lb.Add(whatMatched);
                s.WriteLine(sr.Value);
            }));

            if (seeAndRespond != null)
            {
                foreach (var item in seeAndRespond)
                {
                    Trace.WriteLine($"DumpTillFind:  -> also looking for '{item.Key}' and will respond with '{item.Value}'");
                }
            }

            // All the actions together
            var expect_actions = new[] { matchText_action, matchEOL_action }
            .Concat(seeAndRespond_actions)
            .ToArray();

            // When is time up? If we are supposed to refresh the timeout then everytime the data changes in the buffer, we will want
            // to update the timeout.
            var timesUp          = DateTime.Now + TimeSpan.FromSeconds(secondsTimeout);
            var streamDataLength = new ValueHasChanged <long>(() => s.Length);

            streamDataLength.Evaluate();

            while (timesUp > DateTime.Now)
            {
                // Make sure the connection hasn't dropped. We won't get an exception later on if that hasn't happened.
                if (!client.IsConnected)
                {
                    throw new SSHConnectionDroppedException($"Connection to {client.ConnectionInfo.Host} has been dropped.");
                }

                // Wait for some sort of interesting text to come back.
                var howLongToWait = MinTime(timesUp - DateTime.Now, TimeoutGranularity);
                var seenText      = await Task.Factory.FromAsync(
                    s.BeginExpect(howLongToWait, null, null, expect_actions),
                    s.EndExpect);

                if (gotmatch)
                {
                    break;
                }

                // Reset the timeout if data has come in and we are doing that.
                if (refreshTimeout && streamDataLength.HasChanged)
                {
                    timesUp = DateTime.Now + TimeSpan.FromSeconds(secondsTimeout);
                }

                // Check to see if we should fail
                if (failNow != null && failNow())
                {
                    throw new SSHCommandInterruptedException("Calling routine requested termination of command");
                }
            }

            // Done. IF there is anything that doesn't include a complete line in there, then dump it.
            lb.DumpRest();
            if (!gotmatch)
            {
                var tmpString = lb.ToString();
                Debug.WriteLine($"Waiting for '{matchText}' back from host and it was not seen inside of {secondsTimeout} seconds. Remaining in buffer: '{tmpString}'");
                throw new TimeoutException($"Waiting for '{matchText}' back from host and it was not seen inside of {secondsTimeout} seconds. Remaining in buffer: '{tmpString}'");
            }
        }