SshStream.Expect() breaks code when SshStream is no longer valid - c#

Im trying to do automation over SSH but the server is faulty and does not implement exec channel properly so I ended up doing a workaround using CreateShellStream(). I can expect that upon running the program a connection wouldnt be available and disconnections are a thing. My solution:
while(!_cancellationToken.IsCancellationRequested))
{
ShellStream stream = null;
while(stream == null)
{
stream = await GetSshStream();
}
while(stream.CanWrite && stream.CanRead)
{
stream.WriteLine(command);
//this breaks everything if stream is not valid
var rep = stream.Expect(new Regex(#"[$>]"));
var delimiters = new[] { " ", "\r\n", "\t" };
var values = rep.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
DealWithValues(values);
}
}
This works and waits for connection and once connected starts coms. The problem arises with that stream.CanWrite && stream.CanRead is not enough to detect that stream is healthy and once connection is lost and stream becomes invalid and used with Expect(); everything breaks. Jumps out of all loops, goes through try {} catch{} and even makes Visual Studio debugger steping break down and continue the program in another thread (multi threaded program). Is there a way to stop this from happening and throwing execution back to first while? I could possibly create a new stream every time I need access to the server but since Im polling parameters about once a second I wouldnt want to have the overhead of reconnecting each time.

I misundertood that thread dissapearing ment code execution stopped. Instead thread sleeps waiting for input. Expect has a timeout overload and I should of been using it.

Related

Process confliction C#

I have the following code:
while (condition == true)
{
//First part
using (var stream = File.Create(audioPath))
{
using (WaveFileWriter writer = new WaveFileWriter(stream, waveFormat))
{
writer.Write(audioBytes.ToArray(), 0, audioBytes.ToArray().Length);
}
}
//Second part
using (Process.Start("cmd.exe", commands)) { };
Thread.Sleep(1000);
}
The first part saves a byte array to an audio file, then the second part of my code runs a .cmd file that does some processing on the code. However, this above code returns the error
the process cannot access the file (audioPath) because it is being used by another process.
I have read some other answers and have encountered this problem before but always managed to solve it with a using statement.
Both parts run correcly independently (when the other part is commented out). I am running this on Windows Server 2016 if that has any affect. I have added permissions to the folder/file also and because they both work independently, I doubt it's a permissions issue.
Is it possible that the using statement is not disposing correctly?
Are you really generating files by the same name?
audioPath doesn't seem to change.
while (condition == true)
{
//First part
using (var stream = File.Create(audioPath))
{
using (WaveFileWriter writer = new WaveFileWriter(stream, waveFormat))
{
writer.Write(audioBytes.ToArray(), 0, audioBytes.ToArray().Length);
}
}
//Second part
using (Process.Start("cmd.exe", commands)) { };
Thread.Sleep(1000);
}
Consider the following:
The auditPath is written.
The cmd-command starts using it - you don't wait for it to finish.
Since you don't wait for it to finish, the loop enters the next iteration
and a new auditPath is written while the cmd-command already is using
the "previous" one.
alternatively
Before the cmd-command actually has started (but after the Process.Start() has
already completed), the loop comes to the next iteration and opens a new "version"
of auditPath, writing to it.
The cmd-command finally starts to access the file and you get the seen error.
All in all you have a race condition here. Make sure you wait for Process to finish,
e.g.
using (var proc = Process.Start(...))
{
proc.WaitForExit();
// You might want to check `proc.ExitCode`, etc.
}
before running the next loop-cycle.
Key take-away: Process.Start() is not synchronous. If you need to wait for the launched command to finish, you need to explicitly do it, otherwise it continues to run in the background and might interfere with your other logic - as it currently does.
I don't know if this would help, but you could try getting rid out of one using and use other constructor of WaveFileWriter:
using (WaveFileWriter writer = new WaveFileWriter(fileName, waveFormat))
{
writer.WriteData(testSequence, 0, testSequence.Length);
}

C# streamreader readtoend freeze up

I have the following code to read the time from time.nist.gov:
TcpClient client = new TcpClient();
var result = client.BeginConnect("129.6.15.28", 13, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success || !client.Connected)
// Timeout
else{
streamReader = new StreamReader(client.GetStream());
var response = streamReader.ReadToEnd();
//code
}
The problem is that sometimes ReadToEnd get frozen indefinitely, I assume because it does not reach and end.
Is it possible to set a timeout for this operation?
Or maybe a better option to read the server response?
Thanks.
According to MSDN:
ReadToEnd assumes that the stream knows when it has reached an end. For interactive protocols in which the server sends data only when you ask for it and does not close the connection, ReadToEnd might block indefinitely because it does not reach an end, and should be avoided.
Do you know how much you're reading? If so, you can use Read().
EDIT:
I tested this code (well, something very similar) and found that ReadToEnd works fine, unless port 13 is blocked, in which case it also runs without returning for me as well. So, check your firewall before doing this.
Better is Hans's suggestion of using an existing, well-tested NTP lib.

RasConnectionNotification after computer resumes from sleep

I've got a project called DotRas on CodePlex that exposes a component called RasConnectionWatcher which uses the RasConnectionNotification Win32 API to receive notifications when connections on a machine change. One of my users recently brought to my attention that if the machine comes out of sleep mode, and attempts to redial the connection, the connection goes into a loop indicating the connection is already being dialed even though it isn't. This loop will not end until the application is restarted, even if done through a synchronous call which all values on the structs are unique for that specific call, and none of it is retained once the call completes.
I've done as much as I can to fix the problem, but I fear the problem is something I've done with the RasConnectionNotification API and using ThreadPool.RegisterWaitForSingleObject which might be blocking something else in Windows.
The below method is used to register 1 of the 4 change types the API supports, and the handle to associate with it to monitor. During runtime, the below method would be called 4 times during initialization to register all 4 change types.
private void Register(NativeMethods.RASCN changeType, RasHandle handle)
{
AutoResetEvent waitObject = new AutoResetEvent(false);
int ret = SafeNativeMethods.Instance.RegisterConnectionNotification(handle, waitObject.SafeWaitHandle, changeType);
if (ret == NativeMethods.SUCCESS)
{
RasConnectionWatcherStateObject stateObject = new RasConnectionWatcherStateObject(changeType);
stateObject.WaitObject = waitObject;
stateObject.WaitHandle = ThreadPool.RegisterWaitForSingleObject(waitObject, new WaitOrTimerCallback(this.ConnectionStateChanged), stateObject, Timeout.Infinite, false);
this._stateObjects.Add(stateObject);
}
}
The event passed into the API gets signaled when Windows detects a change in the connections on the machine. The callback used just takes the change type registered from the state object and then processes it to determine exactly what changed.
private void ConnectionStateChanged(object obj, bool timedOut)
{
lock (this.lockObject)
{
if (this.EnableRaisingEvents)
{
try
{
// Retrieve the active connections to compare against the last state that was checked.
ReadOnlyCollection<RasConnection> connections = RasConnection.GetActiveConnections();
RasConnection connection = null;
switch (((RasConnectionWatcherStateObject)obj).ChangeType)
{
case NativeMethods.RASCN.Disconnection:
connection = FindEntry(this._lastState, connections);
if (connection != null)
{
this.OnDisconnected(new RasConnectionEventArgs(connection));
}
if (this.Handle != null)
{
// The handle that was being monitored has been disconnected.
this.Handle = null;
}
this._lastState = connections;
break;
}
}
catch (Exception ex)
{
this.OnError(new System.IO.ErrorEventArgs(ex));
}
}
}
}
}
Everything works perfectly, other than when the machine comes out of sleep. Now the strange thing is when this happens, if a MessageBox is displayed (even for 1 ms and closed by using SendMessage) it will work. I can only imagine something I've done is blocking something else in Windows so that it can't continue processing while the event is being processed by the component.
I've stripped down a lot of the code here, the full source can be found at:
http://dotras.codeplex.com/SourceControl/changeset/view/68525#1344960
I've come for help from people much smarter than myself, I'm outside of my comfort zone trying to fix this problem, any assistance would be greatly appreciated!
Thanks! - Jeff
After a lot of effort, I tracked down the problem. Thankfully it wasn't a blocking issue in Windows.
For those curious, basically once the machine came out of sleep the developer was attempting to immediately dial a connection (via the Disconnected event). Since the network interfaces hadn't finished initializing, an error was returned and the connection handle was not being closed. Any attempts to close the connection would throw an error indicating the connection was already closed, even though it wasn't. Since the handle was left open, any subsequent attempts to dial the connection would cause an actual error.
I just had to make an adjustment in the HangUp code to hide the error thrown when a connection is closed that has already been closed.

odd behavior with C# ftp client class

I found an ftp client class in c# over a year ago and have been using it in a process that uploads files on a nightly basis. A few days ago we started having a problem where it would time out. I'm not well versed in this so I'm not sure why it's doing this.
When the program starts uploading a file it checks to see if it's logged in and if not, it calls the login method. In that method is this block of code.
if (this.resultCode != 230)
{
this.sendCommand("PASS " + password);
if (!(this.resultCode == 230 || this.resultCode == 202))
{
this.cleanup();
throw new FtpException(this.result.Substring(4));
}
}
On the line that says this.sendCommand("PASS"... it goes into this code.
private void sendCommand(String command)
{
if (this.verboseDebugging) Debug.WriteLine(command, "FtpClient");
Byte[] cmdBytes = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray());
clientSocket.Send(cmdBytes, cmdBytes.Length, 0);
this.readResponse();
}
If I let the program run, it times out. However if I step through it into the sendCommand method it executes fine. Does anyone know why it would work fine when I step through it? Nothing on our end has changed and I've been told nothing on the client's end has changed so I'm stumped. Thanks.
Let it run in debug mode and when it freezes hit pause so you can see exactly what line it's hung up on.
If it starts the transfer - it'll not need to login again, unless the connection interrupts and your client tries to reconnect which will result in relogin.
I strongly suggest into looking if the client supports "NOOP" command (used to keep the control connection alive while the data is transferred over data connection). That's the most common problem with FTP implementations.

Thread stops doing its job

We have a C# application that connects to a FTP server, downloads some files, disconnects, and after a certain amount of time (selected by the user through the UI) reconnects and repeats the process. We implemented this using BackgroundWorker, but we noticed that after running for a longer time, the program stopped logging its actions, both in the UI and the log file.
At that point, there were no files for it to download, so we uploaded some and it resumed activity as if nothing had happened.
The problem was that the regular users had no way of knowing that the program was still working, so we decided to implement it using our own threading. We did a simpler program, to rule out any other problems, and this one only connects to the FTP and disconnects. It stopped displaying messages just like BackgroundWorker (one time after 2 hours, one time after 22 hours, without any pattern that we could find, and on a computer that did nothing else).
DoFTPWork += new DoFTPWorkDelegate(WriteFTPMessage);
FTPWorkThread = new Thread(new ParameterizedThreadStart(Process));
//seData is the FTP login info
FTPWorkThread.Start(seData);
and the FTP method is:
private void Process(object seData1)
{
seData = (SEData)seData1;
while (!stopped)
{
try
{
ftp = null;
ftp = new FTP_Client();
if (ftp.IsConnected)
{
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Ftp disconnected from " + seData.host + "\r\n";
ftp.Disconnect();
}
ftp.Connect(seData.host, 21);
ftp.Authenticate(seData.userName, seData.password);
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Ftp connected to " + seData.host + "\r\n";
error = false;
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Trying to reconnect in 5 seconds\r\n";
System.Threading.Thread.Sleep(5000);
SlaveEventArgs ev = new SlaveEventArgs();
ev.Message = logMessages;
txtLog.Invoke(DoFTPWork, ev);
System.Threading.Thread.Sleep(200);
logMessages = "";
}
catch (Exception ex)
{
logMessages = "";
if (ftp.IsConnected)
{
ftp.Disconnect();
}
ftp.Dispose();
logMessages += DateTime.Now + "\t" + "ERR" + "\t" + ex.Message + "\r\n";
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Trying to reconnect in 5 seconds\r\n";
SlaveEventArgs ev = new SlaveEventArgs();
ev.Message = logMessages;
txtLog.Invoke(DoFTPWork, ev);
System.Threading.Thread.Sleep(5 * 1000);
error = true;
}
}
}
WriteFTPMessage displays the message in a TextBox and in the original program wrote to a .txt file.
If I'm understanding you correctly this while(!stopped) loop is the loop that is running for several hours? If that is the case, where are you terminating your ftp connection if anywhere? The only time you close it in the code you've posted is if an exception is thrown, otherwise you simply dereference the object and create a new one which is a pretty serious resource leak and at least contributing to the problem if not causing it.
Also it seems that ftp is globally accessible. Are you accessing it anywhere using a different thread? Is the object thread safe??
EDIT:
The biggest issue I see here is design. Not that I'm trying to bag on you or anything but you've got all sorts of operations intermixed. Threading, logging and ftp access code all in the same function.
What I would recommend is restructuring your program. Create a method much like the following:
// Called by thread
void MyThreadOperation()
{
while(!stopped)
{
// This is poor design in terms of performance.
// Consider using a ResetEvent instead.
Thread.Sleep(5000);
try
{
doFTPDownload();
}
catch(Exception ex)
{
logMessage(ex.ToString());
}
}
}
doFTPDownload() should be self contained. The FTP object should be created and opened inside the function when it is called and prior to it finishing it should be closed. This same concept should be applied to logMessage() as well. I would also recommend using a database to store log messages instead of a file so that locking issues don't complicate matters.
I know this isn't an answer in that you may still experience issues since I can't say for certain what could be the cause. However I'm confident with a little design restructuring you will be much better able to track down the source of the problem.
I would suggest putting anything that can go wrong in the catch block (in particular the bit which disconnects from the FTP server) in its own try/catch block. In addition, log something as soon as you've caught the exception, before doing anything else - that way you're more likely to be able to tell if the logging dies half way through for some reason.
Also, add a log message to the end of the while loop so that you can tell if it's finished "normally".
I'd suggest using adplus when the issue reproduces and getting yourself a hang dump. Analyze in Windbg and SoS.
Is that in a Winforms application? Maybe the ISynchronizeInvoke implementation is hanging. Is this running as an interactive user?
Rupert: I have added ftp.Disconnect() after the catch block and started it again. I've checked the original application and we disconnected before reconnecting, so while it can influence the problem, I don't think it's causing it.
There are no other threads accessing it, so there are no problems there.
Jon: I will, thanks for the suggestion.
JD: It is a Windows application, and after selecting the delay and FTP connect data, the user doesn't give any input. I'll look into ISynchronizeInvoke
I think you'll have to work on making it more thread safe. You have a lot of shared fields: ftp, logMessages, error.
For instance this part:
ev.Message = logMessages;
txtLog.Invoke(DoFTPWork, ev);
System.Threading.Thread.Sleep(200);
logMessages = "";
Sounds to me like you're trying to solve a multithreading problem by sleeping and crossing your fingers you slept enough...
you could solve this via:
ev.Message = logMessages.Clone();
txtLog.Invoke(DoFTPWork, ev);
or use a different way of communicating.
Instead of the stopped boolean you could use a ManualResetEvent, which is a thread safe communication method. And for error you could use the same, or a Semaphore.
The nice thing about the ManualResetEvent is that you can use it to sleep your thread without locking it up completely. If I'm not mistaken the only way to stop your thread while it's sleeping is to call a thread.Abort. If you use the ManualResetEvent you could do the following:
if (!shouldStop.WaitOne(5000))
{
// do thread stuff
}
else
{
// do cleanup stuff and exit thread.
}
The nice thing is, you'll say I want to know if the event was signalled or not, but I will wait 5 seconds for it to signal or else I'll continue as not signalled.
So if your application decides to quit after 3 seconds in the sleep, it can just do a shouldStop.Set() and the thread will stop. It's still possible that the thread is in the process of communicating with the ftp server, so after the set you should do a thread.Join() to wait for it to exit.
I'm not saying your problem is related to my suggestions, if not I'm only trying to help reducing the possible causes.

Categories