Пример #1
2
        /// <summary>
        /// Dump the input until we see a particular string in the returning text.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="refreshTimeout">If we see something back from the host, reset the timeout counter</param>
        /// <param name="p"></param>
        /// <param name="failNow">Function that returns true if we should throw out right away</param>
        private void DumpTillFind(ShellStream s, string matchText, 
            Action<string> ongo = null, 
            bool dontdumplineofmatch = true, 
            int secondsTimeout = 60*60, 
            bool refreshTimeout = false,
            Func<bool> failNow = null
            )
        {
            var lb = new LineBuffer(ongo);
            if (dontdumplineofmatch)
            {
                lb.Suppress(matchText);
            }

            var timeout = DateTime.Now + TimeSpan.FromSeconds(secondsTimeout);
            bool gotmatch = false;
            while (timeout > DateTime.Now)
            {
                s.Expect(TimeSpan.FromMilliseconds(100), new ExpectAction(matchText, l => { lb.Add(l); gotmatch = true; }));
                gotmatch = gotmatch || lb.Match(matchText);
                if (gotmatch)
                    break;

                var data = s.Read();
                if (data != null && data.Length > 0 && refreshTimeout)
                {
                    timeout = DateTime.Now + TimeSpan.FromSeconds(secondsTimeout);
                }

                lb.Add(data);

                if (failNow != null && failNow())
                {
                    throw new SSHCommandInterruptedException("Calling routine requested termination of command");
                }
            }
            if (!gotmatch)
            {
                throw new TimeoutException(string.Format("Waiting for '{0}' back from host and it was not seen inside of {1} seconds.", matchText, secondsTimeout));
            }
            lb.DumpRest();
        }
Пример #2
0
 public void MatchOnCharByChar()
 {
     var l = new LineBuffer();
     l.Add("b");
     l.Add("a");
     Assert.IsFalse(l.Match("bash"));
     l.Add("s");
     l.Add("h");
     Assert.IsTrue(l.Match("bash"));
 }
Пример #3
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}'");
            }
        }
Пример #4
0
 public void TestEmptyLineWidth()
 {
     var l = new LineBuffer(null);
     Assert.IsFalse(l.Match("bogus"));
 }
Пример #5
0
 public void SimpleMatchWithExtra()
 {
     var l = new LineBuffer();
     l.Add("bogusbashdude");
     Assert.IsTrue(l.Match("bash"));
 }
Пример #6
0
 public void SimpleMatch()
 {
     var l = new LineBuffer();
     l.Add("bash");
     Assert.IsTrue(l.Match("bash"));
 }
Пример #7
0
 public void MissMatchOnNewLine()
 {
     var l = new LineBuffer();
     l.Add("bash" + CrLf + "dude");
     Assert.IsFalse(l.Match("bash"));
 }