Pcap.Net PacketCommunicator.Dispose() close my application without any error - c#

I am using Pcap.Net take Pcap File and transmit all it's packet through my machine Network Adapter.
So in order to do that i am using the code example Sending packets using Send Buffer:
class Program
{
static void Main(string[] args)
{
string file = #"C:\file_1.pcap";
string file2 = #"C:\file_2.pcap";
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
// Take the selected adapter
PacketDevice selectedOutputDevice = allDevices[1];
SendPackets(selectedOutputDevice, file);
SendPackets(selectedOutputDevice, file2);
}
static void SendPackets(PacketDevice selectedOutputDevice, string file)
{
// Retrieve the length of the capture file
long capLength = new FileInfo(file).Length;
// Chek if the timestamps must be respected
bool isSync = false;
// Open the capture file
OfflinePacketDevice selectedInputDevice = new OfflinePacketDevice(file);
using (PacketCommunicator inputCommunicator = selectedInputDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
using (PacketCommunicator outputCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
// Allocate a send buffer
using (PacketSendBuffer sendBuffer = new PacketSendBuffer((uint)capLength))
{
// Fill the buffer with the packets from the file
Packet packet;
while (inputCommunicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
{
//outputCommunicator.SendPacket(packet);
sendBuffer.Enqueue(packet);
}
// Transmit the queue
outputCommunicator.Transmit(sendBuffer, isSync);
inputCommunicator.Dispose();
}
outputCommunicator.Dispose();
}
//inputCommunicator.Dispose();
}
}
}
In order to send packet Pcap.Net offers 2 ways:
Send buffer.
Send each packet using SendPacket().
Now after finish to send my 2 files (like in my example) i want to use the Dispose() to free resources.
when using the first option all works fine and this finish to handle my 2 Pcap files.
When using the second option SendPacket() (currently in my code example this is as a comments) after the first file finish my application is closing and not reach to the second file.
I try it also in Console Application and in WPF and in both cases same result.
With UI (WPF) my application GUI just close without any error.
Any suggestions what could cause this ?

When you use the using keyword it means you implicitly call Dispose() at the end of the scope.
If you call Dispose() explicitly as well, it means you call Dispose() twice on the same instance, which is likely to crash your program.

Related

Why do these two StreamWriter constructors give me different results?

Long story short I am trying to send a string via TcpClient using StreamWriter.
Without changing any other code except swapping out these samples. They produce different results.
In code sample 1 the StreamReader picks up that it has DataAvailable and the message is received.
In code sample 2 it does not have DataAvailable so no message is received. I need to keep my underlying stream open hence needing to use the constructor of StreamWrite in sample 2.
Sample 1 - Write Method
public void SendMessage(string message)
{
message = "TestMessage";
//WORKING - Sample 1
using (var sw = new StreamWriter(stream))
{
sw.Write(message);
sw.Flush();
}
}
Sample 2 - Write Method
public void SendMessage(string message)
{
message = "TestMessage";
//NOT WORKING - Sample 2
var encoding = new UTF8Encoding(false, true);
using (var sw = new StreamWriter(stream, encoding, 1024, true))
{
sw.Write(message);
sw.Flush();
}
}
Read Method
public string ReadMessage()
{
if (!stream.DataAvailable)
return null;
//I have also tried
//if(sr.Peek() == 0)
// return null;
string message = sr.ReadToEnd();
return message;
}
NOTE: If I put both samples together with the working one last I get the message received "TestMessageTestMessage" so it is definitely writing to stream however it is not setting DataAvailable to true?
Any Idea's why?
The problem is your ReadToEnd() command which blocks indefinitely on a NetworkStream which has no end until closed. I tested your code and I went past the DataAvailable query and blocked on the ReadToEnd() command.
Your method that uses a constructor that allows the BaseStream to stay open means that you never have an end to your stream. When the working method closes the stream the ReadMessage method returns with everything in the stream.
The solution: Do not attempt to read to the end. Read in blocks while the data is available or introduce a terminating character and read to that character.
From 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.

How do I write a counterpart program that can be called remotely to perform computations on a remote machine

I have written a program that generates checksums on files. Everything works fine on a local machine but slows down immensely and turns to **** when I branch out to remote machines due to network speed (obviously).
How do I go about writing a counterpart program that can be called upon remotely to calculate the checksums on the remote machine and respond with the hash?
Ideally I would love full remote deployment but I have access to the remote machine for install and setup.
Targets are Windows and Ubuntu/FreeBSD using Mono.
Edit
I didn't explain myself as well as I had thought. I have a server which hosts a large number of large files and rather than stream those files over the network to my personal computer to calculate the checksum (as I have been) I'm looking for a way to run a daemon on the server that I can ask to calculate the checksum for a file it hosts locally and give me the hash.
And now a complete reformation of the answer. While still commenting as well as I could, I've tried to keep it as "basic" / "general" as I could without creating loose ends.
Main Program (Normal Method)
public async Task<byte[]> ConnectToCounterpart(string dataToSend)
{
// === Sending empty strings breaks the program ===
if (String.IsNullOrEmpty(dataToSend))
return null;
// === Variables n' Stuff ===
string counterPartIP = "127.0.0.1"; // The ip of the computer running counterpart program. (127.0.0.1 is the localhost/current computer).
int counterPartPort = 50_000; // The port which the counterpart program listens to
// === Getting a connection ===
TcpClient client = new TcpClient(counterPartIP, counterPartPort); // Connect to the counterpart program
NetworkStream nwStream = client.GetStream(); // Get the networkStream between the main and counterpart program
nwStream.ReadTimeout = 5_000; // Give the counterpart program 5 seconds to do its thing
// === Convert the "dataToSend" to a byte-array ===
byte[] bytesToSend = Encoding.UTF7.GetBytes(dataToSend); // An array with the bytes of the string (UTF7 lets you keep "cpecial characters like Æ, Ø, Å, Á etc.")
// === Send the file-bytes ===
await nwStream.WriteAsync(bytesToSend, 0, bytesToSend.Length); // Send the file-bytes to the counterpart program
// ==========================================
// At this point counterpart is doing work
// ==========================================
byte[] returnBytes = new byte[client.ReceiveBufferSize]; // The byte-array this method returns
try
{
// === Recieve the reply ===
int numberOfBytesRecieved = await nwStream.ReadAsync(returnBytes, 0, client.ReceiveBufferSize); // Receve the checksum from the counterpart and tthe ammount of sent bytes
// === Crop return-array to the recieved bytes ===
Array.Resize(ref returnBytes, numberOfBytesRecieved);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error while retrieving"); // Show error
returnBytes = null; // Set returnbytes to null
}
// === Close and dispose stream ===
nwStream.Close();
nwStream.Dispose();
// === Return the byte-array ===
return returnBytes;
}
In this piece of code you've probably noticed "async", "Task<byte[]>" and "await". "Task<byte[]>" is the same as "byte[]" (kinda) and is used because the "async" modifier requires it. (About async programming: https://msdn.microsoft.com/da-dk/library/hh156513(v=vs.110).aspx)
The returned type will in any case still be "byte[]". "Async" and "Await" will be explained further in a "bit" (Byte, bit... Puns).
Counterpart Code (BackgroundWorker)
private void BackgroundWorkerCalculate_Counterpart_DoWork(object sender, DoWorkEventArgs e)
{
// === Variables n' Stuff ===
int listeningPort = 50_000; // The port which the counterpart program listens to
// === Start listening ===
TcpListener listener = new TcpListener(IPAddress.Any, listeningPort); // Listen to the port
listener.Start();
// Infinite loop for infinite computations
while (true)
{
// === Getting a connection ===
TcpClient connection = listener.AcceptTcpClient();
NetworkStream nwStream = connection.GetStream();
// === Get the recieved bytes ===
byte[] recievedBytes = new byte[connection.ReceiveBufferSize]; // Create a buffer for the incomming file-bytes
int numberOfBytesRecieved = nwStream.Read(recievedBytes, 0, connection.ReceiveBufferSize); // Read the bytes to the buffer
// === Convert recieved bytes to a string ===
string recievedString = Encoding.UTF7.GetString(recievedBytes, 0, numberOfBytesRecieved);
// === Understanding the recieved data ===
/* Lets say recievedString == "[path]" */
byte[] replyBytes = new byte[] { 1 }; // Bytes to reply to the main program
try
{
using (MD5 md5 = MD5.Create()) // Create the hashing protocol
{
using (FileStream fileStream = new FileStream(recievedString, FileMode.Open)) // Open the file to hash
{
replyBytes = md5.ComputeHash(fileStream); // replyBytes now contains the hash
}
}
}
catch
{ } // If file doesn't exist, then replyBytes stays as { 1 }, which will be returned if things goes wrong
// === Send the reply to main program ===
nwStream.Write(replyBytes, 0, replyBytes.Length);
}
}
This code still does the same: Recieves some data and returns some data. You can now modify the "Understanding the recieved data" part to your needs. For example checking if the received path is a file or a directory, thus differentiating between "GetChecksum" (referring to a file) and "GetSubelements" (referring to a directory).
Main Program (Usage)
private async void ButtonCalculate_Counterpart_Click(object sender, EventArgs e)
{
// This is how you use the method
byte[] replyBytes = await ConnectToCounterpart(#"folder\file.txt");
// "async" makes the given method "asyncronous", so that it runs parallell to other tings
// "await" will prevent a time-consumeing method-call from "halting" or "blocking" the main process.
// Check if things went wrong
if (replyBytes == new byte { 1 }) // As mentioned ealier in the backgroundWorker code
{
MessageBox.Show("Something went wrong with the hashing. Is the path correct?", "Could not hash")
return;
}
// If you want the reply as a normal string
string replyString = Encoding.UTF7.GetString(replyBytes, 0, replyBytes.Length);
// If you want the reply as a checksum
string checkSum = BitConverter.ToString(replyBytes);
}
The comments here should explain things.
Note: You can easily use other encryptions besides UTF7, just be consistent througout the code.
Note 2: If the data sent ever becomes larger than 50 kB, then there is a risk of not all data being sent, because of the way I've programmed this. If that becomes a problem, I can do some changes. Those changes are just more complicated.
Note 3: If you want to access the counterpart from a seperate network (over the internet and not locally), then you'll need to do some port forwarding on the router to which the counterart is connected.
Note 4: Remember that, if you pass a path like this "Folder\File.txt" to the counterpart, then the counterpart will look at the directory "C:\Users\...\...\FolderWithProgramExe\Folder\File.txt". If you instead pass "C:\Folder\File.txt" (note "C:\" in the beginning) to the counterpart, then the counterpart will look at exactly the location "C:\Folder\File.txt" on the computer.
I hope this will be of use to you now. As said, I've tried to keep the code as "plastic" / "easily modifiable" as possible, so that you can adjust it to your needs.

.NET C# reading from serial after NModBus call

I'm issuing a NModBus call (setting a register to 1) to a sensor that then triggers a transmission of binary data from the sensor via the serial port.
As long as I only read/write registers via NModBus, everything works just fine but when I want to read this returning byte flow, it just doesn't work.
I've tried a few different approaches:
Using the same SerialPort
Using two different SerialPort objects (on the same port of course) in case there were trailing buffers
Reading "synchronously" immediately after the NModBus call
Reading using SerialPortDataReceived
Adding timeouts here and there (including adding waiting times on the sensor itself before starting transmission)
Etc.
Depending on the approach, I may read 4 (four) bytes but I think they are the ModBus answer to the write register call. No way to retrieve the rest of the flow (a few hundred bytes). And yes, in case you were wondering, I have verified via a separate tool that such flow is indeed transmitted. :-P
I have exchanged information via serial port in other programs with no particular problems so I was wondering if the fact that I'm using NModBus then standard serial port operations on the same port is generating concerns?
The code - that is supposed to be pretty basic - looks like:
using (SerialPort serialForModBus = new SerialPort(Port))
{
// Basic serial port settings
Open(serialForModBus);
// Create ModBus RTU master
IModbusSerialMaster master = CreateMaster(serialForModBus);
// Write register to trigger reading...
master.WriteMultipleRegisters(SLAVE_ID, SensorModBusRegisters.COMMAND_SEND_LOGS, new ushort[] { (ushort)1 });
}
// Now read...
using (SerialPort serialToReadLogs = new SerialPort(Port))
{
Open(serialToReadLogs);
serialToReadLogs.ReadTimeout = 10000;
// Externalize reading to separate class (that will also do the parsing..)
SensorLogSerialReader logReader = new SensorLogSerialReader();
serialToReadLogs.DataReceived += logReader.SerialPortDataReceived;
}
// In SensorLogSerialReader
public void SerialPortDataReceived(object senderSerialPort, SerialDataReceivedEventArgs e)
{
SerialPort sender = (SerialPort)senderSerialPort;
List<byte> bytes = new List<byte>();
try
{
bool moreToRead = (sender.BytesToRead != 0);
int cur;
while (moreToRead)
{
cur = sender.ReadByte();
bytes.Add((byte)cur);
moreToRead = (sender.BytesToRead != 0);
}
Done = true;
}
catch (...)
}
Any idea? Am I missing something "evident"?
Thank you!
Note: I've seen an post that may be similar but remained unanswered

How to restart a Network Stream after a SocketException

I have a piece of code that reads a JSON stream from a server on the public internet. I am trying to make the connection a little more robust by catching the exception and trying to restart it on a given interval but I haven't been able to figure out how to restart it.
My stream code is as follows
TcpClient connection = new TcpClient(hostname, port);
NetworkStream stream = connection.GetStream();
thread = new Thread(ProcessStream);
thread.Start(stream);
My ProcessStream method is
private void ProcessStream(object stream)
{
Stream source = (NetworkStream)stream;
byte[] line;
int count;
const int capacity = 300;
ReadState readState;
while ((readState = ReadStreamLine(source, out line, out count, capacity)) != ReadState.EOF && _stopFeed == false)
{
if (readState != ReadState.Error && count > 4)
{
byte[] line1 = new byte[count];
Array.Copy(line, line1, count);
Process(line1); // return ignored in stream mode
}
else
{
ReadFail(line, count);
}
}
}
and my ReadStream function takes the stream s, does an s.ReadByte and then catches the exception when the network connection is broken. It is here that I am not sure how to try and restart the stream on a timed basis. It does not restart automatically when the network is restored.
That is not possible. It is like you calling your friend on the phone and he hangs up in the middle of a conversation. No matter how long you wait, you'll never hear from him again. All you can do is hang-up the phone and dial the number again. Unless the server supports restartable downloads (use HttpWebRequest.AddRange), you'll have to download the json again from the beginning.
If this happens a lot, so it can't be explained by the server going offline or getting overloaded, do keep in mind that the server might well be doing this on purpose. Usually because you exceeded some kind of quota. Talk to the server owner, they typically have a paid plan to allow you to use more resources.
From what I can tell, you instantiate your TcpClient before you start your method. So, in order to restart your stream, you need to re-instantiate or re-initialize your connection stream before trying again.
try
{
// Do something
}
catch (Exception ex)
{
// Caught your exception, might be ideal to log it too
// Have a count, if count is less than goal
// Call your method again
if (count < 5)
{
// re-initialize or re-instantiate connection
TcpClient connection = new TcpClient(host, port);
NetworkStream stream = connection.GetStream();
ProcessStream(stream);
}
}
I hope this helps.
You coculd at first add your stream to a static list of running streams and after finishing reading remove it from there.
Remember to use locking!
Then in the NetworkGone-Catch you can copy your list to a "todoAfterNetworkIsUpAgain"-List and start a timer that checks for network and after your network is up again restarts reading the streams again.
This Might look a bit tuff but its not the case.
Use Recursion and threading in a better way and your problem might get resolved
For Recursion
http://www.dotnetperls.com/recursion
For Threading
Take a look to msdn documentation or take consepts from albahari

Clickonce application and file handler behavior

I have a clickonce application, and I have set up several file handlers for this application (for the sake of this example, I want to handle files with either the .aaa or .bbb extensions).
If I select a single file with one of these extensions, my application starts up as expected, everything is good. But if I select multiple files and open them (either by hitting Enter or by right clicking and selecting Open), then multiple instances of my aopplication are started up - one instance per file that was selected.
This is not the behavior I expected, I want just one instance to start with multiple file entries in the AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Can this be achieved, or is my expectation incorrect?
Edit:
Just to elaborate: we have followed the single instance approach as mentioned by #Matthias, the first instance to start up creates a named server pipe. Subsequent instances then start up, detect that they are secondary, communicate their command line arguments (filename) through to the main instance via the named pipe, then quit. The main instance receives the filename via the named pipe, and does its thing (starts up a file import wizard).
The issue comes when a user selects several files (i.e. 5 files), then selects to open those files in the application. Instead of getting one secondary instance starting with 5 file names supplied on the command line, I'm getting 5 secondary instances of the application starting, each with a single filename on the command line. Each of these then creates a client named pipe and communicates that filename to the main instance - so the server named pipe receives 5 separate messages.
Follow up thoughts:
after chatting about this it occurs to me that maybe this is just the way registered file handlers work, maybe it is not related to clickonce. Maybe the solution is for the server named pipe to pause after receiving each message and to attempt to queue messages before actioning them?
You can achieve this by implementing a single instance application. If the application is already running (second call), you can use named pipes to inform the application (first call) of a file open event.
EDIT
Found a code snippet from an earlier project. I want to underline that the code definitely needs improvements, but it should be a good point where you can start from.
In your static main:
const string pipeName = "auDeo.Server";
var ownCmd = string.Join(" ", args);
try
{
using (var ipc = new IPC(pipeName))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new ServerForm();
ipc.MessageReceived += m =>
{
var remoteCmd = Encoding.UTF8.GetString(m);
form.Invoke(remoteCmd);
};
if (!string.IsNullOrEmpty(ownCmd))
form.Invoke(ownCmd);
Application.Run(form);
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
if (string.IsNullOrEmpty(ownCmd))
return;
var msg = Encoding.UTF8.GetBytes(ownCmd);
IPC.SendMessage(pipeName, msg);
}
The IPC class:
public class IPC : IDisposable
{
public IPC(string pipeName)
{
Stream = new NamedPipeServerStream(pipeName,
PipeDirection.InOut,
1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
AsyncCallback callback = null;
callback = delegate(IAsyncResult ar)
{
try
{
Stream.EndWaitForConnection(ar);
}
catch (ObjectDisposedException)
{
return;
}
var buffer = new byte[2000];
var length = Stream.Read(buffer, 0, buffer.Length);
var message = new byte[length];
Array.Copy(buffer, message, length);
if (MessageReceived != null)
MessageReceived(message);
Stream.Disconnect();
// ReSharper disable AccessToModifiedClosure
Stream.BeginWaitForConnection(callback, null);
// ReSharper restore AccessToModifiedClosure
};
Stream.BeginWaitForConnection(callback, null);
}
private NamedPipeServerStream Stream
{
get;
set;
}
#region IDisposable Members
public void Dispose()
{
if (Stream != null)
Stream.Dispose();
}
#endregion
public static void SendMessage(string pipeName, byte[] message)
{
using (var client = new NamedPipeClientStream(".", pipeName))
{
client.Connect();
client.Write(message, 0, message.Length);
client.Close();
}
}
~IPC()
{
Dispose();
}
public event MessageHandler MessageReceived;
}
The answer to the problem was to have a small delay at the server end of the pipe. In summary:
the first started instance of the app is the owner of the server end of the pipe, subsequent instances of the app are a client
When receiving a message from a client, a timer was started, if the timer was already started then it was reset. The passed file name is added to a list.
The timer delay was set to 2 seconds, once the tick event occurred (so it had been 2 seconds since the last client communication) the single instance server would take the appropriate action with the list of file names
This is not the behavior I expected, I want just one instance to start with multiple file entries in the AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Can this be achieved, or is my expectation incorrect?
My expectation was incorrect - you can only pass through a single file name to a registered file handler, each file name starts a separate instance of the handler.

Categories