Post a reply

Options
Add an Attachment

If you do not want to add an Attachment to your Post, please leave the Fields blank.

(maximum 10 MB; please compress large files; only common media, archive, text and programming file formats are allowed)

Options

Topic review

solutionsville

Anytime.
martin

Re: DebugLogLevel Enable/Disable

Thanks for sharing your code.
solutionsville

DebugLogLevel Enable/Disable

Looks like the forum logged me out when I posted this topic.
Guest

DebugLogLevel Enable/Disable

Martin, I wanted a way to enable or disable the DebugLogging & SessionLogging programatically in my app that i built.

On my main form, I added a ToolStripMenu item called Debug and made it Checked type. I then added a bool to the Class file that handles the WinSCP session items, it sets the log paths, and the DebugLogLevel.

Forwarded for info and for use if anyone else is looking for how to do it. Maybe something to add to an example in the documentation section?




using System;

using System.Collections.Concurrent;
using System.Data.SqlClient;
using System.IO;
using System.Threading;
using WinSCP;

namespace CnaFirmware
{
    public enum UpdateState
    {
        Idle,               // black
        Working,            // black
        Uploading,

        // complete:
        CompleteNoError,    // green

        // errors:
        Aborted,
        CompleteWithError   // red
    };

    public class UploadTask
    {
        ConcurrentQueue<string> ConsoleQueue;
        public string cna_ip;
        string fingerprint;
        readonly string ImageFileName;
        public string CnaVersion;
        readonly string TargetVersion;
        public string CurrentFileName;
        public double CurrentFileProgress;
        private static string _lastFileName;
        bool abort = false;
        Session session;
        Thread TaskThread;
        readonly string LogFileName;
        public string UpdatedFirmwareVersion;
        public bool WarningShown;

        // this string is for the user checking status during the update from the UI:
        public string status;

        // this status determines the color of the item in the list box
        public UpdateState state;

        // these allow the main form to track progress and repaint the item when done
        public bool UpdateSuccess;
        public bool JobComplete;
        public bool NeedUiUpdate;
        public bool Verbose;
        // Set WinSCP DebugLogLevel Boolean
        public bool debug;

        // need states so the checkedlistbox knows what color to paint this.

        // this class will push firmware to one CNA.
        // inputs:  IP address of CNA
        //          Fingerprint string
        //          image file (*.run) to upload
        //          queue for sending messages back to main (UI) thread

        // status:  idle
        //          transfering
        //          load (remote script)
        //          complete

        // logging: only log start, errors, or success to the UI. everything goes to the log file for this cna.

        // update 20180618:  fingerprint is no longer required: WinSCP will scan for fingerprint, then upload firmware.


        public UploadTask(string cnaip,
                          string fprint,
                          ConcurrentQueue<string> q,
                          string filename)
        {
            // DebugLogLevel=0 by default
            debug = false;
            cna_ip = cnaip;
            WarningShown = false;
            UpdateSuccess = false;
            fingerprint = fprint;
            ConsoleQueue = q;
            ImageFileName = filename;
            LogFileName = string.Format("{0}\\{1}.log", Globals.LogPath + @"\CNAip\", cna_ip);

            // for checking file transfer progress:
            CurrentFileName = string.Empty;
            CurrentFileProgress = 0;
            status = "idle";
            state = UpdateState.Idle;
            JobComplete = false;
            NeedUiUpdate = false;
            UpdatedFirmwareVersion = "";

            // firmware version of target CNA
            CnaVersion = "";

            // new firmware version to be uploaded
            TargetVersion = ExtractCnaVersion(filename);
        }

        // This is to extract the version of the Firmware file
        string ExtractCnaVersion(string filename)
        {
            // ...CNA15xxvX_X_X.run   10,16
            string v = "0.0.0";
            string f = Path.GetFileName(filename);
            int posv = f.IndexOf("v");
            int posr = f.IndexOf(".run");
            posv++;
            try
            {
                v = f.Substring(posv, posr - posv);
            }
            catch (Exception) { }
            return v.Replace("_", ".");
        }
        void _PostStatus(string s)
        {
            // set status string to what's going on.
            ConsoleQueue.Enqueue(string.Format("!{0}: {1}", cna_ip, s));
        }

        void NewState(UpdateState s)
        {
            state = s;
            NeedUiUpdate = true;
        }

        public void SetCnaVersion(byte[] data)
        {
            // Set Expected CNA version
            if (data[0] < 2) return;
            string v = string.Format("{0}.{1}.{2}", data[1], data[2], data[3]);
            Log("SetCnaVersion:" + v);
            CnaVersion = v;
        }

        public void Start()
        {
            // Start the Thread
            TaskThread = new Thread(() => TaskThreadCode());
            TaskThread.Start();
        }
        void Logui(string s)
        {
            // send to UI
            ConsoleQueue.Enqueue(string.Format("{0}: {1}", cna_ip, s));
            // and file it
            Log(s);
        }
        void Log(string s)
        {
            Directory.CreateDirectory(Globals.LogPath + @"\CNAip");
            File.AppendAllText(LogFileName, string.Format("{0} {1}: {2}{3}", DateTime.Now.ToString("yyyyMMdd.HHmmss.fff"), cna_ip, s, Environment.NewLine));
        }

        // Upload Status and progress
        public string GetStatus()
        {
            string s = "";
            if (status == "uploading binary")
            {
                s = string.Format("{0}: uploading binary ({1:P0})", cna_ip, CurrentFileProgress);
            }
            else
            {
                s = status;
                s = string.Format("{0}: {1}", cna_ip, status);
            }
            return s;
        }

        public void TaskThreadCode()
        {
            Logui("Starting update");
            NewState(UpdateState.Working);
            try
            {
                // first get the CNA SSH fingerprint
                SessionOptions sessionOptions = new SessionOptions
                {
                    Protocol = Protocol.Scp,
                    HostName = cna_ip
                };

                sessionOptions.AddRawSettings("KEX", "ecdh,dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN");
                //Session session;
                using (session = new Session())
                {
                    fingerprint = session.ScanFingerprint(sessionOptions, "MD5");
                    Log($"Fingerprint: {fingerprint}");
                }

                // Set up session options for firmware transfer
                // The same configuration is used on all devices
                sessionOptions = new SessionOptions
                {
                    Protocol = Protocol.Scp,
                    HostName = cna_ip,
                    UserName = "root",
                    Password = "root",
                    SshHostKeyFingerprint = fingerprint
                };
                // This is the same for all connections
                sessionOptions.AddRawSettings("AuthGSSAPI", "1");
                sessionOptions.AddRawSettings("Cipher", "aes,blowfish,3des,chacha20,WARN,arcfour,des");
                sessionOptions.AddRawSettings("KEX", "ecdh,dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN");

                status = "uploading binary";

                using (session = new Session())
                {
                    try
                    {
                        fingerprint = session.ScanFingerprint(sessionOptions, "MD5");
                        Log($"Fingerprint: {fingerprint}");
                        // Will continuously report progress of transfer
                        Directory.CreateDirectory(Globals.LogPath + @"\Debug");
                        // If MenuItem is checked then DebugLogLevel = 2, else Default of 0.
                        // also sets the DebugLogPath and SessionLogPath values.
                        if (debug == true)
                        {
                            session.DebugLogLevel = 2;
                            session.DebugLogPath = Globals.LogPath + @"\Debug\WSCPDebug.log";
                            session.SessionLogPath = Globals.LogPath + @"\Debug\WSCPSession.log";
                        }

                        else
                        {
                            session.DebugLogLevel = 0;
                            session.DebugLogPath = null;
                            session.SessionLogPath = null;
                        }

                        session.FileTransferProgress += SessionFileTransferProgress;
                        session.OutputDataReceived += SessionOutputDataReceived;
                        // session.DisableVersionCheck = true;
                        // Connect
                        Log("Opening session");
                        session.Open(sessionOptions);
                        // Upload files
                        TransferOptions transferOptions = new TransferOptions()
                        {
                            TransferMode = TransferMode.Binary
                        };
                        // Transfer Results
                        TransferOperationResult transferResult;
                        transferResult = session.PutFiles(ImageFileName, "/var/tmp/*", false, transferOptions);
                    }
                    catch (Exception ex)
                    {
                        Logui("WinSCP: " + ex.Message);
                        ConsoleQueue.Enqueue("@" + ex.Message);
                        status = "WinSCP Error";
                        NewState(UpdateState.CompleteWithError);
                        JobComplete = true;
                        _PostStatus("Failed");
                        // terminate thread
                        return;
                    }
                    if (abort) session.Close();

                    // Write to log upload status
                    Log("File transfer succeeded");

                    // PutFiles has completed: now run bash script.
                    status = "waiting for remote load";
                    // Change to the remote directory.
                    session.ExecuteCommand("cd /tmp");
                    // Modify the permissions on the *.run file.
                    session.ExecuteCommand("chmod 777 *.run");
                    // Log entry status update.
                    Log("Running remote command: load");

                    // This command will display the completion of the Load command results, including version information.
                    session.ExecuteCommand(string.Format("./{0} --load", Path.GetFileName(ImageFileName)));

                    // note: you should never get here!

                    // Eprom load completed, executing reboot.
                    status = "remote load complete";
                    // Add entery to log that session is closing.
                    Log("Closing WinSCP session");
                    // Close the session.
                    session.Close();
                }
            }
            catch (Exception e)
            {
                // either the update was aborted by the user, or an error occurred, or the upload was successful.
                // so - this thread will always exit from here.
                if (e.Message == "Aborted.")
                {
                    // Abort the Threads.
                    if (abort)
                    {
                        // user abort
                        status = "User abort";
                        NewState(UpdateState.Idle);
                        Logui("Update cancelled by user");
                    }
                    else
                    {
                        // normal (success)
                        if (UpdateSuccess)
                        {
                            status = "updating database";
                            Log("Updating database record");
                            UpdateDbRecord();
                            UpdatedFirmwareVersion = TargetVersion;
                            Logui("Update successful");
                            NewState(UpdateState.CompleteNoError);
                            status = "CNA update complete";
                        }
                    }
                }
                else
                {
                    // a real error occurred, and this thread will exit with an error status.
                    status = "Error";
                    NewState(UpdateState.CompleteWithError);
                    Logui(string.Format("Error: {0}", e.Message));
                }
            }
            JobComplete = true;
        }

        void SessionFileTransferProgress(object sender, FileTransferProgressEventArgs e)
        {
            // This displays the file transfer status percentage.
            if (abort) session.Abort();
            //New line for every new file
            if ((_lastFileName != null) && (_lastFileName != e.FileName))
            {
                Log(string.Format("Uploading: {0}", e.FileName));
            }

            // Print transfer progress
            _PostStatus(string.Format("Uploading: {0:P0}", e.FileProgress));

            // Remember a name of the last file reported
            _lastFileName = e.FileName;
            CurrentFileProgress = e.FileProgress;
        }

        void SessionOutputDataReceived(object sender, OutputDataReceivedEventArgs e)
        {
            if (abort) session.Abort();

            if (
                   e.Data.Contains("Starting")
                || e.Data.Contains("Opening")
                || e.Data.Contains("Searching")
                || e.Data.Contains("Connecting")
                || e.Data.Contains("Updating")
                || e.Data.Contains("Validating")
                || e.Data.Contains("Authenticating...")
                || e.Data == "File transfer succeeded"
                || e.Data == "Valid firmware"
                || e.Data == "Update successful"
                )
                _PostStatus(e.Data);

            Log(e.Data);
            if (e.Data.Contains("Updating CNA") && e.Data.Contains("success"))
            {
                UpdateSuccess = true;
                _PostStatus("Firmware update was successful.");
                // done: abort the session now
                session.Abort();
            }
        }

        public void Cancel()
        {
            abort = true;
            //logui("Upload Cancelled by User!");
        }
        void UpdateDbRecord()
        {
            // This routine is for updating the Firmware version number in the nms_cfg database.
            SqlConnection NmsRt;
            using (NmsRt = new SqlConnection(Globals.ConnectionString))
            {
                try
                {
                    NmsRt.Open();
                }
                catch (Exception)
                {
                    Logui("Unable to open NMS database.");
                    return;
                }
                string query = string.Format("update cna_firmware set firmware_rev = '{0}' where ip_address = '{1}'", TargetVersion, cna_ip);
                try
                {
                    using (SqlCommand sql = new SqlCommand(query, NmsRt)) sql.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    Logui("UpdateDbRecord: " + ex.Message);
                }
            }
        }
    }
}
[/code]