Esempio n. 1
0
        /// <summary>
        /// Run Pscp synchronously
        /// </summary>
        /// <param name="result">Result object where results </param>
        /// <param name="args">The args to send to pscp</param>
        /// <param name="argsToLog">The args that are logged or can be returned in status messages</param>
        /// <param name="inlineOutHandler">Inline handler for output</param>
        /// <param name="inlineErrHandler">Inline handler for error</param>
        /// <param name="successOutHandler">Handler for output of successful operation</param>
        private void RunPscp(
            PscpResult result,
            string args,
            string argsToLog,
            Func <string, bool> inlineOutHandler,
            Func <string, bool> inlineErrHandler,
            Action <string[]> successOutHandler)
        {
            if (!File.Exists(Options.PscpLocation))
            {
                result.SetError(string.Format(LocalizedText.PscpClient_RunPscp_Pscp_missing, Options.PscpLocation), null);
            }
            else if (Session.Username == null)
            {
                result.SetError(LocalizedText.PscpClient_RunPscp_UserName_is_null, null);
            }
            else if (Session.Host == null)
            {
                result.SetError(LocalizedText.PscpClient_RunPscp_Host_is_null, null);
            }
            else if (Session.Port < 0)
            {
                result.SetError(string.Format(LocalizedText.PscpClient_RunPscp_Invalid_port, Session.Port), null);
            }
            else
            {
                Process           proc         = NewProcess(Options.PscpLocation, args);
                Timer             timeoutTimer = null;
                AsyncStreamReader outReader    = null;
                AsyncStreamReader errReader    = null;
                try
                {
                    // Start pscp
                    Log.InfoFormat("Starting process: file={0}, args={1}", Options.PscpLocation, argsToLog);
                    proc.Start();

                    // Timeout when no output is received
                    timeoutTimer = new Timer(
                        (x) =>
                    {
                        // timeout
                        SafeKill(proc);
                        result.SetErrorFormat(LocalizedText.PscpClient_RunPscp_Process_timed_out, argsToLog);
                    },
                        null, Options.TimeoutMs, Timeout.Infinite);

                    // Async read output/err.  Inline actions to quick kill the process when pscp prompts user.
                    // NOTE: Using BeginReadOutput/ErrorReadLine doesn't work here.  Calls to read an empty stream
                    //       will block (e.g. "user's password:"******"OUT",
                        proc.StandardOutput,
                        strOut =>
                    {
                        bool keepReading = true;
                        bool completed   = false;
                        if (strOut == PuttyInteractiveAuth || strOut.Contains("assword:"))
                        {
                            result.StatusCode = ResultStatusCode.RetryAuthentication;
                            Log.Debug("Username/Password invalid or not sent");
                            SafeKill(proc);
                            keepReading = false;
                        }
                        else if (inlineOutHandler != null)
                        {
                            completed = inlineOutHandler(strOut);
                        }
                        timeoutTimer.Change(completed ? Timeout.Infinite : Options.TimeoutMs, Timeout.Infinite);
                        return(keepReading);
                    });
                    errReader = new AsyncStreamReader(
                        "ERR",
                        proc.StandardError,
                        strErr =>
                    {
                        bool keepReading = true;
                        bool completed   = false;
                        if (strErr != null && strErr.Contains(PuttyNoKey))
                        {
                            result.SetError("Host key not cached.  Connect via putty to cache key then try again", null);
                            SafeKill(proc);
                            keepReading = false;
                        }
                        else if (inlineErrHandler != null)
                        {
                            completed = inlineErrHandler(strErr);
                        }
                        timeoutTimer.Change(completed ? Timeout.Infinite : Options.TimeoutMs, Timeout.Infinite);
                        return(keepReading);
                    });

                    // start process and wait for results
                    Log.DebugFormat("WaitingForExit");
                    proc.WaitForExit();

                    Log.InfoFormat("Process exited, pid={0}, exitCode={1}", proc.Id, proc.ExitCode);
                    timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    string[] output = outReader.StopAndGetData();
                    string[] err    = errReader.StopAndGetData();

                    string outputStr = String.Join("\r\n", output);
                    if (proc.ExitCode == 0 && outputStr.Contains(PuttyUnableToOpen))
                    {
                        // bad path
                        int idx = outputStr.IndexOf(PuttyUnableToOpen, StringComparison.Ordinal);
                        result.SetErrorFormat(outputStr.Substring(idx));
                    }
                    else if (proc.ExitCode == 0)
                    {
                        // successful operation
                        successOutHandler?.Invoke(output);
                    }
                    else
                    {
                        // some kind of error
                        if (result.StatusCode != ResultStatusCode.Success)
                        {
                            Log.Debug("Skipping output check since proactively killed process.");
                        }
                        else if (output.Contains(PuttyArgumentsHelpHeader))
                        {
                            result.SetErrorFormat("Invalid arguments sent to pscp, args={0}, output={1}", args, output);
                        }
                        else if (err.Contains(PuttyHostDoesNotExist))
                        {
                            result.SetErrorFormat("Host does not exist.  {0}:{1}", Session.Host, Session.Port);
                        }
                        else
                        {
                            result.SetErrorFormat("Unknown error.  exitCode={0}, out='{1}', err='{2}'", proc.ExitCode, String.Join("|", output), String.Join("|", err));
                        }
                    }
                }
                finally
                {
                    SafeKill(proc);
                    SafeDispose(timeoutTimer, proc, outReader, errReader);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Run Pscp synchronously
        /// </summary>
        /// <param name="result">Result object where results </param>
        /// <param name="args">The args to send to pscp</param>
        /// <param name="argsToLog">The args that are logged or can be returned in status messages</param>
        /// <param name="inlineOutHandler">Inline handler for output</param>
        /// <param name="inlineErrHandler">Inline handler for error</param>
        /// <param name="successOutHandler">Handler for output of successful operation</param>
        private void RunPscp(
            PscpResult result,
            string args,
            string argsToLog,
            Func <string, bool> inlineOutHandler,
            Func <string, bool> inlineErrHandler,
            Action <string[]> successOutHandler)
        {
            if (!File.Exists(this.Options.PscpLocation))
            {
                result.SetError(string.Format("Pscp missing, path={0}.", this.Options.PscpLocation), null);
            }
            else if (this.Session.Username == null)
            {
                result.SetError("UserName is null", null);
            }
            else if (this.Session.Host == null)
            {
                result.SetError("Host is null", null);
            }
            else if (this.Session.Port < 0)
            {
                result.SetError("Invalid port: " + this.Session.Port, null);
            }
            else
            {
                Process           proc         = NewProcess(this.Options.PscpLocation, args);
                Timer             timeoutTimer = null;
                AsyncStreamReader outReader    = null;
                AsyncStreamReader errReader    = null;
                try
                {
                    // Start pscp
                    Log.InfoFormat("Starting process: file={0}, args={1}", this.Options.PscpLocation, argsToLog);
                    proc.Start();

                    // Timeout when no output is received
                    timeoutTimer = new Timer(
                        (x) =>
                    {
                        // timeout
                        SafeKill(proc);
                        result.SetErrorFormat("Process timed out, args={0}", argsToLog);
                    },
                        null, this.Options.TimeoutMs, Timeout.Infinite);

                    // Async read output/err.  Inline actions to quick kill the process when pscp prompts user.
                    // NOTE: Using BeginReadOutput/ErrorReadLine doesn't work here.  Calls to read an empty stream
                    //       will block (e.g. "user's password:"******"OUT",
                        proc.StandardOutput,
                        strOut =>
                    {
                        bool keepReading = true;
                        bool completed   = false;
                        if (strOut == PUTTY_INTERACTIVE_AUTH || strOut.Contains("assword:"))
                        {
                            result.StatusCode = ResultStatusCode.RetryAuthentication;
                            Log.Debug("Username/Password invalid or not sent");
                            SafeKill(proc);
                            keepReading = false;
                        }
                        else if (inlineOutHandler != null)
                        {
                            completed = inlineOutHandler(strOut);
                        }
                        timeoutTimer.Change(completed ? Timeout.Infinite : this.Options.TimeoutMs, Timeout.Infinite);
                        return(keepReading);
                    });
                    errReader = new AsyncStreamReader(
                        "ERR",
                        proc.StandardError,
                        strErr =>
                    {
                        bool keepReading = true;
                        bool completed   = false;
                        if (strErr != null && strErr.Contains(PUTTY_NO_KEY))
                        {
                            result.SetError("Host key not cached.  Connect via putty to cache key then try again", null);
                            SafeKill(proc);
                            keepReading = false;
                        }
                        else if (inlineErrHandler != null)
                        {
                            completed = inlineErrHandler(strErr);
                        }
                        timeoutTimer.Change(completed ? Timeout.Infinite : this.Options.TimeoutMs, Timeout.Infinite);
                        return(keepReading);
                    });

                    // start process and wait for results
                    Log.DebugFormat("WaitingForExit");
                    proc.WaitForExit();

                    Log.InfoFormat("Process exited, pid={0}, exitCode={1}", proc.Id, proc.ExitCode);
                    timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    string[] output = outReader.StopAndGetData();
                    string[] err    = errReader.StopAndGetData();

                    string outputStr = String.Join("\r\n", output);
                    if (proc.ExitCode == 0 && outputStr.Contains(PUTTY_UNABLE_TO_OPEN))
                    {
                        // bad path
                        int idx = outputStr.IndexOf(PUTTY_UNABLE_TO_OPEN);
                        result.SetErrorFormat(outputStr.Substring(idx));
                    }
                    else if (proc.ExitCode == 0)
                    {
                        // successful operation
                        if (successOutHandler != null)
                        {
                            successOutHandler(output);
                        }
                    }
                    else
                    {
                        // some kind of error
                        if (result.StatusCode != ResultStatusCode.Success)
                        {
                            Log.Debug("Skipping output check since proactively killed process.");
                        }
                        else if (output.Contains(PUTTY_ARGUMENTS_HELP_HEADER))
                        {
                            result.SetErrorFormat("Invalid arguments sent to pscp, args={0}, output={1}", args, output);
                        }
                        else if (err.Contains(PUTTY_HOST_DOES_NOT_EXIST))
                        {
                            result.SetErrorFormat("Host does not exist.  {0}:{1}", this.Session.Host, this.Session.Port);
                        }
                        else
                        {
                            result.SetErrorFormat("Unknown error.  exitCode={0}, out='{1}', err='{2}'", proc.ExitCode, String.Join("|", output), String.Join("|", err));
                        }
                    }
                }
                finally
                {
                    SafeKill(proc);
                    SafeDispose(timeoutTimer, proc, outReader, errReader);
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Run Pscp synchronously
        /// </summary>
        /// <param name="result">Result object where results </param>
        /// <param name="args">The args to send to pscp</param>
        /// <param name="argsToLog">The args that are logged or can be returned in status messages</param>
        /// <param name="inlineOutHandler">Inline handler for output</param>
        /// <param name="inlineErrHandler">Inline handler for error</param>
        /// <param name="successOutHandler">Handler for output of successful operation</param>
        void RunPscp(
            PscpResult result,
            string args,
            string argsToLog,
            Func<string, bool> inlineOutHandler,
            Func<string, bool> inlineErrHandler,
            Action<string[]> successOutHandler)
        {
            if (!File.Exists(this.Options.PscpLocation))
            {
                result.SetError(string.Format("Pscp missing, path={0}.", this.Options.PscpLocation), null);
            }
            else if (this.Session.Username == null)
            {
                result.SetError("UserName is null", null);
            }
            else if (this.Session.Host == null)
            {
                result.SetError("Host is null", null);
            }
            else if (this.Session.Port < 0)
            {
                result.SetError("Invalid port: " + this.Session.Port, null);
            }
            else
            {

                Process proc = NewProcess(this.Options.PscpLocation, args);
                Timer timeoutTimer = null;
                AsyncStreamReader outReader = null;
                AsyncStreamReader errReader = null;
                try
                {
                    // Start pscp
                    Log.InfoFormat("Starting process: file={0}, args={1}", this.Options.PscpLocation, argsToLog);
                    proc.Start();

                    // Timeout when no output is received
                    timeoutTimer = new Timer(
                        (x) =>
                        {
                            // timeout
                            SafeKill(proc);
                            result.SetErrorFormat("Process timed out, args={0}", argsToLog);
                        },
                        null, this.Options.TimeoutMs, Timeout.Infinite);

                    // Async read output/err.  Inline actions to quick kill the process when pscp prompts user.
                    // NOTE: Using BeginReadOutput/ErrorReadLine doesn't work here.  Calls to read an empty stream
                    //       will block (e.g. "user's password:"******"OUT",
                        proc.StandardOutput,
                        strOut =>
                        {
                            bool keepReading = true;
                            bool completed = false;
                            if (strOut == PUTTY_INTERACTIVE_AUTH || strOut.Contains("assword:"))
                            {
                                result.StatusCode = ResultStatusCode.RetryAuthentication;
                                Log.Debug("Username/Password invalid or not sent");
                                SafeKill(proc);
                                keepReading = false;
                            }
                            else if (inlineOutHandler != null)
                            {
                                completed = inlineOutHandler(strOut);
                            }
                            timeoutTimer.Change(completed ? Timeout.Infinite : this.Options.TimeoutMs, Timeout.Infinite);
                            return keepReading;
                        });
                    errReader = new AsyncStreamReader(
                        "ERR",
                        proc.StandardError,
                        strErr =>
                        {
                            bool keepReading = true;
                            bool completed = false;
                            if (strErr != null && strErr.Contains(PUTTY_NO_KEY))
                            {
                                result.SetError("Host key not cached.  Connect via putty to cache key then try again", null);
                                SafeKill(proc);
                                keepReading = false;
                            }
                            else if (inlineErrHandler != null)
                            {
                                completed = inlineErrHandler(strErr);
                            }
                            timeoutTimer.Change(completed ? Timeout.Infinite : this.Options.TimeoutMs, Timeout.Infinite);
                            return keepReading;
                        });

                    // start process and wait for results
                    Log.DebugFormat("WaitingForExit");
                    proc.WaitForExit();

                    Log.InfoFormat("Process exited, pid={0}, exitCode={1}", proc.Id, proc.ExitCode);
                    timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    string[] output = outReader.StopAndGetData();
                    string[] err = errReader.StopAndGetData();

                    string outputStr = String.Join("\r\n", output);
                    if (proc.ExitCode == 0 && outputStr.Contains(PUTTY_UNABLE_TO_OPEN))
                    {
                        // bad path
                        int idx = outputStr.IndexOf(PUTTY_UNABLE_TO_OPEN);
                        result.SetErrorFormat(outputStr.Substring(idx));
                    }
                    else if (proc.ExitCode == 0)
                    {
                        // successful operation
                        if (successOutHandler != null)
                        {
                            successOutHandler(output);
                        }
                    }
                    else
                    {
                        // some kind of error
                        if (result.StatusCode != ResultStatusCode.Success)
                        {
                            Log.Debug("Skipping output check since proactively killed process.");
                        }
                        else if (output.Contains(PUTTY_ARGUMENTS_HELP_HEADER))
                        {
                            result.SetErrorFormat("Invalid arguments sent to pscp, args={0}, output={1}", args, output);
                        }
                        else if (err.Contains(PUTTY_HOST_DOES_NOT_EXIST))
                        {
                            result.SetErrorFormat("Host does not exist.  {0}:{1}", this.Session.Host, this.Session.Port);
                        }
                        else
                        {
                            result.SetErrorFormat("Unknown error.  exitCode={0}, out='{1}', err='{2}'", proc.ExitCode, String.Join("|", output), String.Join("|", err));
                        }
                    }
                }
                finally
                {
                    SafeKill(proc);
                    SafeDispose(timeoutTimer, proc, outReader, errReader);
                }

            }
        }