Reading and processing command output line by line in SSH.NET - c#

I am working on a home project that needs to execute some commands via SSH, read back the responses and display them on a web page. A lot of the time it does work, but now and then i get some inconsistent behavior, for example certain lines of output are missed that would instruct on what to do next, this results in a hung session, and a requirement to restore IIS.
I have included the code below, like I said I am not a full time developer, so its gonna be a mess, but hopefully someone can point me in the right direction to understand what i got so wrong, and what i need to change, i wont learn if you just past code snippets up, id much rather attempt to try and fix what i have.
using (SshClient ssh = new SshClient("192.168.0.119", "x", "x."))
{
ssh.Connect();
ShellStream shell = ssh.CreateShellStream("Tail", 0, 0, 0, 0, 1024);
StreamWriter wr = new StreamWriter(shell);
StreamReader rd = new StreamReader(shell);
wr.AutoFlush = true;
if (extract)
{
Console.WriteLine("Downloading DataZIP");
ssh.RunCommand("wget " + zipURL);
}
bool reading = shell.CanRead;
wr.WriteLine("cd " + remoteFilePath + packagename + " && docker build -t dockerfile .");
while (reading)
{
Clients.Caller.builderOut(shell.ReadLine().ToString());
if (shell.ReadLine().ToString().Contains("Successfully"))
{
Clients.Caller.builderOut("Build Complete");
reading = false;
}
if (shell.ReadLine().ToString().Contains("returned a non-zero code: "))
{
goto end;
}
}
if (data.Type == TemplateType.Data)
{
wr.WriteLine("cd " + remoteFilePath + packagename + " && docker tag dockerfile " + data.Repository + "/" + data.packagename.ToLower() + ":data.Type");
wr.WriteLine("cd " + remoteFilePath + packagename + " && docker push " + data.Repository + "/" + data.packagename.ToLower() + ":data.Type");
}
reading = shell.CanRead;
while (reading)
{
Clients.Caller.builderOut("Pushing this will take a moment");
if (shell.ReadLine().ToString().Contains("digest:"))
{
Clients.Caller.builderOut("Pushed");
reading = false;
}
}
Clients.Caller.builderOut("End");
ssh.Disconnect();
ssh.Dispose();
}
What I think I got wrong
I think I get these errors due to the way I'm reading the console output. I think that that data changes so fast we miss some:
while (reading)
{
Clients.Caller.builderOut(shell.ReadLine().ToString());
if (shell.ReadLine().ToString().Contains("Successfully"))
{
Clients.Caller.builderOut("Build Complete");
reading = false;
}
if (shell.ReadLine().ToString().Contains("returned a non-zero code: "))
{
goto end;
}
}
So using that each of the 3 checks on the output could I think be be missing some of the lines, as the output is quite speedy, while its reading the value changes so the next check has different init data to check, and thus we skip over what would otherwise be the exit lines or next job lines.

You have to store the line that you read into a variable and do the checks against the stored value:
while (reading)
{
string line = shell.ReadLine();
Clients.Caller.builderOut(line);
if (line.Contains("Successfully"))
{
Clients.Caller.builderOut("Build Complete");
reading = false;
}
if (line.Contains("returned a non-zero code: "))
{
goto end;
}
}

Related

code working well when i put a breakpoint on getresponsedata, but without a breakpoint it does not work

//webservice connection
CRB_WEBSERVICE.CBS_SERVICE.BatchPublicServiceClient proxy = new CRB_WEBSERVICE.CBS_SERVICE.BatchPublicServiceClient("BasicHttpBinding_IBatchPublicService");
proxy.ClientCredentials.UserName.UserName = "";
proxy.ClientCredentials.UserName.Password = "";
string currdte = DateTime.Now.ToString("yyyyMMdd");
//Open Connection for webservice
proxy.Open();
//batchid is a string requested in format the client wants
string batchid = "" + currdte + "_" + "D" + "_" + "**" + "_" + num + "_" + "XML" + "_" + "T";
//generatexml is generating an XML file which is then zipped and sent via //webservice
GenerateXML(batchid);
try
{
//process to send zipped file via webservice
byte[] data = File.ReadAllBytes(batchid + ".zip");
proxy.Begin(batchid);
proxy.PutData(batchid, 1, data);
proxy.Finish(batchid, 1);
var b = proxy.GetBatchInfo(batchid);
// thread so it waits for the response
Thread.Sleep(11000);
// this is where my issue is.if i put a breakpoint i get a response of a //zipped file. if i dont nothing happens
**var result = proxy.GetResponseData(batchid, 1);**
//Thread.Sleep(100);
System.IO.File.WriteAllBytes(#"C:\CBS_WEBSERVICE\Response.zip", result);
}
Please note this is not the whole code. I need assistance as my code is running perfectly when I put a breakpoint on the GetResponseData but if I do not it does not bring a response. I tried adding thread.sleep so it waits for a response from the webservice but still no luck. I have added comments.
I was supposed to check the first parameter: BatchStatus before calling the method GetDataResponse. I read the documentation of the API again. Without the batchstatus GetDataResponse will be null hence code was hanging in release mode and only working in debug mode.
var b = proxy.GetBatchInfo(batchid);
while (b.BatchStatus != CRB_WEBSERVICE.CBS_SERVICE.BatchStatuses.Finished)
{
b = proxy.GetBatchInfo(batchid);
}
if (b.BatchStatus == CRB_WEBSERVICE.CBS_SERVICE.BatchStatuses.Finished)
{
if (b.BatchResult == CRB_WEBSERVICE.CBS_SERVICE.BatchResults.Success)
{
var result = proxy.GetResponseData(batchid, 1);
}
}

If a specific string is not in the file, I'm trying to report a message. I keep getting the same message

I'm reading a text file. If a specific string is not in the file, I'm trying to report a message. I keep getting the same message over again, or, not at all depending on where I put it.
I have moved this (code just above counter++; near the bottom)
"else lbOne.Items.Add(txtID.Text + " does not exist.");" around to every conceivable line with no luck. I know just enough to be dangerous, so could use some help with this.
if (rButtonFind.Checked)
{
int counter = 0;
string line;
System.IO.StreamReader file = new System.IO.StreamReader(#"F:\Quality\CMM Fixtures\fixtures.txt");
if (new FileInfo(#"F:\09 Quality\CMM Fixtures\fixtures.txt").Length == 0)
{
MessageBox.Show("There is no data in the file to search." + "\n" + "There must be at least one fixture" + "\n" + " to not see this message.");
}
while ((line = file.ReadLine()) != null)
{
if (line.Contains(txtID.Text))
{
lbOne.Items.Add(line);
}
else
lbOne.Items.Add(txtID.Text + " does not exist.");
counter++;
}
file.Close();
}
}
As I said, it either lists the "does not exist" message many times, or not at all.
Since you need to know only if the file contains at least one occurrence of the string, then this is the code you need. But you also need to better defend against the file not existing.
I don't know if counter is supposed to be a count of lines read or if it's supposed to indicate a count of times the string is not found. I just assumed it's a count of times the string is not found. But regardless, the scope of counter is within the if block and so there's no use for it unless you intend to do something with it later, in which case you'll have to change its scope.
if (rButtonFind.Checked) {
int counter = 0;
string line;
string filename = #"F:\Quality\CMM Fixtures\fixtures.txt";
System.IO.StreamReader file = new System.IO.StreamReader(filename);
if (new FileInfo(filename).Length == 0) {
MessageBox.Show("There is no data in the file to search." + "\n" + "There must be at least one fixture" + "\n" + " to not see this message.");
} else {
bool found = false;
while ((line = file.ReadLine()) != null) {
if (line.Contains(txtID.Text)) {
lbOne.Items.Add(line);
found = true;
break;
}
}
if (!found) {
lbOne.Items.Add(txtID.Text + " does not exist.");
counter++;
}
}
file.Close();
}
I found the answer by playing with Jeff's code. By simply switching the bool declaration to true, and then the if found to "!true", and removing the break, it works as it should. I would not have gotten this without Jeffs help. I double asterisked the changes I made to Jeffs code that made it work.
bool found = **true**;
while ((line = file.ReadLine()) != null)
{
if (line.Contains(txtID.Text))
{
lbOne.Items.Add(line);
found = **!true**;
}
counter++;
}
if (**found**)
{
lbOne.Items.Add(txtID.Text + " does not exist.");
}
file.Close();

C# system.timers.timer weird behavior

I am trying to implement Bully Coordinator election algorithm. In this algorithm, Coordinator sends the alive message every 10 seconds and all the processes wait for at least 14 seconds to receive alive, if they don't receive the message within that time, they will initiate dead coordinator election.
The problem is AliveTimer (Timer3_Count) is increasing exponentially and active processes are also affecting it. I don't know why it is behaving weirdly.
When the initial coordinator is sending the Alive message then counter works perfectly but after dead coordinator election, it behaves weirdly.
else if (Received_Text.Contains("Alive:"))
{
SetText(Received_Text + "\n");
Coordinator_Alive = true;
Timer3_Counter = 0;
if (Alive_Count == 0)
{
Alive_Count++;
AliveTimer.Interval = (1 * 1000);
AliveTimer.Enabled = true;
AliveTimer.Elapsed += new System.Timers.ElapsedEventHandler(AliveTimer_Elapsed);
AliveTimer.Start();
}
}
The elapsed function is here
I think there is something wrong with my program, I tried everything.
private void AliveTimer_Elapsed(object sender, EventArgs e)
{
Timer3_Counter++;
SetTimer(Timer3_Counter.ToString());
Random rnd = new Random();
int rand_time = rnd.Next(14, 18);
if (Timer3_Counter == 14)
{
AliveTimer.Stop();
Timer3_Counter = 0;
Alive_Count = 0;
if (Coordinator_Alive == false)
{
byte[] buffer = Encoding.ASCII.GetBytes("Dead Coordinator Election: " + txName.Text);
_clientSocket.Send(buffer);
Timer4_Counter = 0;
DeadTimer.Interval = (1 * 1000);
DeadTimer.Elapsed += new System.Timers.ElapsedEventHandler(DeadTimer_Elapsed);
DeadTimer.Enabled = true;
DeadTimer.Start();
}
}
if (Coordinator_Alive == true)
Coordinator_Alive = false;
}
and the dead Coordinator election code is here
else if (Received_Text.Contains("Dead Coordinator Election:"))
{
SetCPID("");
Coordinator_Alive = false;
Alive_Count = 0;
Timer3_Counter = 0;
AliveTimer.Stop();
AliveTimer.Enabled = false;
string output = Regex.Match(Received_Text, #"\d+").Value;
SetText("Dead Coordinator Election Received from Process ID: " + output + "\n");
if (Convert.ToInt32(txName.Text) > Convert.ToInt32(output))
{
byte[] buffer = Encoding.ASCII.GetBytes("Greater Process No: " + txName.Text + " found than " + output + "\n");
_clientSocket.Send(buffer);
SetText("Our Process No: " + txName.Text + " is Greater than " + output + "\n");
Lower_Count++;
byte[] buffer1 = Encoding.ASCII.GetBytes("Dead Coordinator Election: " + txName.Text);
_clientSocket.Send(buffer1);
}
else
{
byte[] Txt_Send = Encoding.ASCII.GetBytes("Our Process No: " + txName.Text + " is less than " + output);
_clientSocket.Send(Txt_Send);
Greater_Count++;
}
}
The full code can be found here
Bully Algorithm
Note: I am using passive server just to broadcast messages from each process
I don't know what causes the problem, but I think you will be able to figure the cause quickly if you log start and stop all all methods and analyse the output.
This would help establish if:
1. As #Idle_Mind suggested, that you are adding more and more handlers
2. The time taken to execute each method creeps up
and more...
I don't know how you app is built but you can even start with Console.WriteLine or Debug.WriteLine.

Index was outside the bounds of the array in MSCORLIB.DLL

I will be amazed if I find a solution for this, since it is very specific and vague, but I figured I would try. I'll try to give as much information as humanly possible, since I've been searching for answers for some time now.
I am building a utility in C# which copies records from a file in a library on the i-series/AS400 and builds an encrypted text file with each record from the AS400 as a comma separated string. In the file, it will have values like filename, fieldvalue1, fieldvalue2, fieldvalue3. I then take that text file to another PC, and run a C# utility which copies that record into the same file name in a library over there on a different i-series machine. Unfortunately, I receive the outside bounds of the array exception in some cases, but I cannot determine why. In the record just prior to the exception, the record looks pretty much the same and it works fine. My code is below in a nutshell. I usually don't give up, but I don't expect to ever figure this out. If someone does, I'll probably sing karaoke tonight.
// Select records from AS400 file and write them to text file
Recordset rs = new Recordset();
sqlQuery = "SELECT * FROM " + dataLibrary + "." + fileName;
try
{
rs.Open(sqlQuery, con);
while (!rs.EOF)
{
int[] fieldLengths;
fieldLengths = new int[rs.Fields.Count];
String[] fieldValues;
fieldValues = new String[rs.Fields.Count];
String fullString = "";
for (i = 0; i < rs.Fields.Count; i++)
{
fieldLengths[i] += rs.Fields[i].DefinedSize;
fieldValues[i] += rs.Fields[i].Value;
}
fullString = fileName + "," + String.Join(",", fieldValues);
fullString = Functions.EncryptString(fullString);
File.AppendAllText(savefile.FileName, fullString + Environment.NewLine);
rs.MoveNext();
}
}
catch (Exception ex)
{
}
cmd.Dispose();
// This gives me a text file of filename, fieldvalue1, fieldvalue2, etc...
// Next, I take the file to another system and run this process:
while ((myString = inputFile.ReadLine()) != null)
{
int stringLength = myString.Length;
String[] valuesArray = myString.Split(',');
for (i = 0; i < valuesArray.Length; i++)
{
if (i == 0)
{
fileName = valuesArray[0];
// Create file if it doesn't exist already
createPhysicalFile(newLibrary, fileName);
SQLStatement = "INSERT INTO " + newLibrary + "." + fileName + "VALUES(";
}
else
{
if (i == valuesArray.Length - 1)
{
SQLStatement += "#VAL" + i + ")";
}
else
{
SQLStatement += "#VAL" + i + ", ";
}
}
}
try
{
using (connection)
{
try
{
connection.Open();
}
catch (Exception ex)
{
}
// Create a new SQL command
iDB2Command command = new iDB2Command(SQLStatement, connection);
for (i = 1; i < valuesArray.Length; i++)
{
try
{
command.Parameters.AddWithValue("#VAL" + i, (valuesArray[i]));
}
catch (Exception ex)
{
}
}
// Just split the array into a string to visually check
// differences in the records
String arraySplit = ConvertStringArrayToString(valuesArray);
// The query gets executed here. The command looks something
// like:
// INSERT INTO LIBNAME.FILENAME VALUES(#VAL!, #VAL2, #VAL3, #VAL4)
// There are actually 320 fields in the file I'm having a problem with,
// so it's possible I'm overlooking something. I have narrowed it down to
// field # 316 when the exception occurs, but in both cases
// field 316 is blanks (when it works and when it doesn't).
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// Here I get the exception out of bounds error in MSCORLIB.DLL.
// Some records are added fine, while others cause this exception.
// I cannot visibly tell any major differences, nor do I see any
// errors in the AS400 job log or anything in C# that would lead me
// down a certain path.
String error = ex.Message;
}
}
For what it's worth, I found this happening one a smaller file in the system and was able to figure out what going on, after painstaking research into the code and the net. Basically, the file file has numeric fields on the i-series. Somehow, the records were written to the file on the original system with null values in the numeric fields instead of numeric values. When storing the original records, I had to do this calculation:
String fieldType = rs.Fields[i].Type.ToString();
object objValue = rs.Fields[i].Value;
if (fieldType == "adNumeric" && objValue is DBNull)
{
fieldValues[i] += "0";
}
else
{
fieldValues[i] += rs.Fields[i].Value;
}
After this, if null values were found in one of the numeric fields, it just put "0" in it's place so that when writing to the new machine, it would put a valid numeric character in there and continue on writing the rest of the values. Thanks for all the advice and moral support. :)

Unauthoriezed Access Exception

i have a cloud database server like application on my computer that i'm hosting my game on. However, every time an user tries to save data i get an UnauthorizedAccessException.
Im running it by admin and i dont have any specias right in my folder so i have no idea what's the problem.
Here's my code:
public const string root = "D:/DATABASE/";
public static void WriteData(string playername, string type, string data)
{
if (!Directory.Exists("D:/DATABASE/" + playername))
{
Directory.CreateDirectory("D:/DATABASE/" + playername);
Directory.CreateDirectory("D:/DATABASE/" + playername + "/weapons");
}
if (type != "Weapon")
{
using (StreamWriter sw = new StreamWriter("D:/DATABASE/" + playername + "/" + type + ".sav"))
{
sw.WriteLine(data);
}
}
else
{
string[] dat = data.Split('%');
using (StreamWriter sw = new StreamWriter("D:/DATABASE/" + playername + "/weapons/" + dat[0] + ".gfa"))
{
string[] lines = dat[1].Split('#');
foreach (string cline in lines)
{
sw.WriteLine(cline);
}
}
}
}
public static string ReadLoadout(string playername)
{
string output = "";
string[] items = new string[2];
using (StreamReader sr = new StreamReader(root + playername + "/loadout.gfl"))
{
items[0] = sr.ReadLine();
items[1] = sr.ReadLine();
}
int c = 0;
foreach (string citem in items)
{
if (c > 0) output += "$";
output += citem + "%" + GetCompressedWeaponFile(playername, citem);
c++;
}
return output;
}
public static string GetCompressedWeaponFile(string playerName, string weaponName)
{
string output = "";
using (StreamReader sr = new StreamReader(root + playerName + "/weapons/" + weaponName))
{
string line = " ";
int c = 0;
while (line != null)
{
line = sr.ReadLine();
if (line != null)
{
if (c > 0) output += "#";
output += line;
}
c++;
}
}
return output;
}
public static void RegisterNewUser(string username, string password, string email)
{
string udir = root + username;
Directory.CreateDirectory(udir);
Directory.CreateDirectory(udir + "/weapons");
Directory.CreateDirectory(udir + "/loadouts");
File.WriteAllText(udir + "/password.sav", password);
File.WriteAllText(udir + "/level.sav", "1");
File.WriteAllText(udir + "/money.sav", "1000");
File.WriteAllText(udir + "/email.sav", email);
File.WriteAllText(udir + "/loadout.gfl", "");
using (StreamWriter sw = new StreamWriter(root + "emails.txt", true))
{
sw.WriteLine(email);
}
Email.Send(email, "New Account Registration", string.Format(mailTemplate, username, password));
}
public static void EditLoadout(string username, string items)
{
File.WriteAllLines(root + username + "/loadout.gfl",items.Split('#'));
}
It is difficult to provide specific help without more information. Here are a few of troubleshooting suggestions:
1) Try running your code on a different machine. Specifically your development computer. Do you still have the same error? If not, then there is indeed a permission problem.
2) Have you tried checking the stack trace of the exception?
When you run the application on your own computer, try using the IDE to display the exception. Yes, the problem may ultimately be in a low-level class, but you should be able to break on the error and go back in the call stack to see which method in your code is actually throwing the error.
3) Check the actual exception, even for a system-level exception.
Chances are, if you are able to debug this in the IDE, that you will see property information that will give you a hint. Is it in a directory method or a file write method? Check additional properties. Somewhere it might give you the text of the path (assuming it's a file issue) that it failed on that that could help narrow things down too.
4) Add Exception handling to your code
This is a good rule of thumb, and you should really do this anyway to make a stronger program. Regardless of who's method you are calling (yours, someone else's, or a system method) you need to determine where it should be handled.
For example, in your code, in the RegisterNewUser() method, consider something like:
public static void RegisterNewUser(string username, string password, string email)
{
try
{
string udir = root + username;
Directory.CreateDirectory(udir);
Directory.CreateDirectory(udir + "/weapons");
Directory.CreateDirectory(udir + "/loadouts");
File.WriteAllText(udir + "/password.sav", password);
File.WriteAllText(udir + "/level.sav", "1");
File.WriteAllText(udir + "/money.sav", "1000");
File.WriteAllText(udir + "/email.sav", email);
File.WriteAllText(udir + "/loadout.gfl", "");
using (StreamWriter sw = new StreamWriter(root + "emails.txt", true))
{
sw.WriteLine(email);
}
Email.Send(email, "New Account Registration", string.Format(mailTemplate, username, password));
}
catch (Exception ex)
{
// Create a method to display or log the exception, with it's own error handler
LogAndDisplayExceptions(ex);
// Send the user a message that we failed to add them. Put this in it's own try-catch block
// ideally, for readability, in it's own method.
try
{
Email.Send(email, "Failed to register", "An error occurred while trying to add your account.");
}
catch (Exception exNested)
{
LogAndDisplayExceptions(exNested);
}
}
}
5) Add a "crash-and-burn" exception handler to "main"
In the method that is your "top method" (it's hard to tell in the snippet you provided since there are few methods that would attempt to write to the disk) you could wrap your code in a try - catch block and print the exception or write it to disk.
If you have having trouble writing the exception to disk, I would suggest creating an error file first, make sure that the user account that is running the program can write to it, and then in the catch block open the file for APPEND. This should make it easier to get to the error text.
6) When all else fails, use the Debug class or Console class to write the traditional "I made it to line x."
While this will not solve your problem, it should help you get more information that will provide more insight into where your code is causing an error.

Categories

Resources