C# Sending request with SSL via TCP doesn't work - c#

here is my code to send TCP request coded in SSL and get the answer from server, but it doesn't work. Debugging and trying to catch exceptions didn't work.
public void SendRequest(string request)
{
byte[] buffer = new byte[2048];
int bytes = -1;
sslStream.Write(Encoding.ASCII.GetBytes(request));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
}
I took that from stackoverflow answer so I'm suprised it doesn't work. Here is my code that receives greeting from server (it works properly):
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = 0;
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
Console.Write(messageData.ToString());

If the sslStream.Read(buffer, 0, buffer.Length); is hanging, it's because the server hasn't sent a response.
Taking a look at your code on github (linked from your other question), it looks like you are using Console.ReadLine() to read commands and then write them to your network stream.
What is happening is that ReadLine() strips off the "\r\n" in the string that it returns, so what you'll need to do when sending it to the server is to add back the "\r\n" so that the server knows that the command is finished (it waits until it gets an EOL sequence before it will respond).
What you could do is in SendRequest(), you could do:
sslStream.Write(Encoding.ASCII.GetBytes(request + "\r\n"));

Related

How do I keep reading data from my Socket to append my buffer

So I'm trying to send an image from my client to my server and I'm sending the entire image as a whole, meaning that I'm not splitting it up into chunks, I'm just sending the entire byte array as is.
CLIENT
private void SendImage(byte[] opcode, byte[] length, byte[] payload)
{
var packet = new byte[payload.Length + length.Length + 1];
Array.Copy(opcode, 0, packet, 0, 1);
//Set the length
Array.Copy(length, 0, packet, 1, length.Length);
Array.Copy(payload, 0, packet, 5, payload.Length);
_clientSocket.Send(packet);
}
This sends just fine, I'm using the OpCode 0x15 which will be interpreted by the server as "there is an image incoming". The length is the payload.Length which I've done this with
var length = BitConverter.GetBytes(myImage.Length);
So it occupies 4 bytes.
So my packet structure looks like this OpCode(1 byte), Length(4 bytes), Payload(imageBytes)
This method works just fine, it sends without any issues what so ever, I only included the code for it so that the next part will make sense.
SERVER
private byte[] _buffer = new byte[1024];
private void ReceiveCallback(IAsyncResult ar)
{
var client = (Socket)ar.AsyncState;
int received = client.EndReceive(ar);
//Temporary buffer
var dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
switch (dataBuf[0])
{
//Received image
case 0x15:
//Read the packet header and check the length of the payload
var length = BitConverter.ToInt32(dataBuf.Skip(1).Take(4).ToArray(), 0);
//This will hold the bytes for the image
var imageBuffer = new byte[length];
//First incoming packet payload (image bytes)
var imgData = dataBuf.Skip(5).ToArray();
//Copy that into the buffer
Array.Copy(imgData, 0, imageBuffer, 0, imgData.Length);
var pos = imgData.Length;
//Keep reading bytes from the incoming stream
while (dataBuf.Length > 0)
{
imgData = new byte[1024];
client.Receive(imgData);
Array.Copy(imgData, 0, imageBuffer, pos, dataBuf.Length);
pos += 1024;
}
//This takes the bytes and creates a bitmap from it
AnotherViewModel.SetImage(imageBuffer);
break;
default:
Debug.WriteLine("Wat");
break;
}
client.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), client);
}
The issues I'm facing is that I don't know how to keep appending the incoming data to the imageBuffer because I want to receive the full image and not just the first 4 bytes and with my while loop I'm currently getting this exception
Destination array was not long enough. Check destIndex and length, and
the array's lower bounds.
Over at this line Array.Copy(imgData, 0, imageBuffer, pos, dataBuf.Length);
How do I properly read the entire image that the client sends to the server?

Handle big bytes when receiving from serial port in c#

I am new in the serial port. Currently, my project is to extract data from the machine. I'm getting data via an event onDataReceive and the machine is sending bytes.
My problem is that the first wave of bytes seemed to be converted correctly to string but in the second batch of bytes, I got garbage data.
Screen Shot of the output(this is the output given by the multi-currency reader machine:
The garbage data is I think the Serial Nos.
Here is my code in onDataReceive method:
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (serialPort.BytesToRead > 0)
{
// Initialize a buffer to hold the received data
byte[] buffer = new byte[serialPort.ReadBufferSize];
//// There is no accurate method for checking how many bytes are read
//// unless you check the return from the Read method
int bytesRead = serialPort.Read(buffer, 0, buffer.Length);
String asd = System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead);
//// For the example assume the data we are received is ASCII data.
tString += Encoding.ASCII.GetString(buffer, 0, bytesRead);
temp += System.Text.Encoding.Unicode.GetString(buffer, 0, bytesRead);
temp2 += System.Text.Encoding.UTF32.GetString(buffer, 0, bytesRead);
System.IO.File.WriteAllText(#"C:\OutputTextFiles\WriteLines.txt", tString);
System.IO.File.WriteAllText(#"C:\OutputTextFiles\WriteLines2.txt", temp);
System.IO.File.WriteAllText(#"C:\OutputTextFiles\WriteLines3.txt", temp2);
}
}
I'm trying to put the output with a txt file.
I hope someone could help me in my problem. Any tips and suggestions in data handling especially bytes?
Without knowing the size of serialPort.ReadBufferSize I can only suspect that your buffer is breaking the encoding bytes of your string. A character can be made of one or more bytes.
The trick is to read all of the bytes before decoding the string.
Try this example program:
var encoding = System.Text.Encoding.Unicode;
var message = "I am new in serial port. Currently my project is to extract data from machine.";
using (var ms = new MemoryStream(encoding.GetBytes(message)))
{
var bytes = new List<byte>();
var buffer = new byte[23];
var bytesRead = ms.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
Console.WriteLine(encoding.GetString(buffer, 0, bytesRead));
bytes.AddRange(buffer.Take(bytesRead));
bytesRead = ms.Read(buffer, 0, buffer.Length);
}
Console.WriteLine(encoding.GetString(bytes.ToArray(), 0, bytes.Count));
}
It will output the following:
I am new in�
猀攀爀椀愀氀 瀀漀爀琀�
. Currently�
洀礀 瀀爀漀樀攀挀琀 �
is to extra�
琀 搀愀琀愀 昀爀漀洀�
machine.
I am new in serial port. Currently my project is to extract data from machine.
The final line is correct because it uses all of the bytes to decode. The previous lines have errors because I've used a buffer size of 23 which breaks the string encoding.

Sending/receiving .txt file from Android to PC, not whole file is sent

I'm trying to make an Android app that sends a .txt file to a Windows Forms application on my computer. The problem is that not the whole file gets sent (I haven't been able to find out whether the problem is on the sending or receiving side). I only get a random part from somewhere in the middle of the .txt file to the receiving side. What am I doing wrong? The strange thing is that it has worked perfectly a few times, but now I'm never getting the beginning or the end of the file.
The Android app is written in Java, and the Windows Forms app is written in C#. filepath is the name of my file. What is the problem here?
Code for Android app (sending file)
//create new byte array with the same length as the file that is to be sent
byte[] array = new byte[(int) filepath.length()];
FileInputStream fileInputStream = new FileInputStream(filepath);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//use bufferedInputStream to read to end of file
bufferedInputStream.read(array, 0, array.length);
//create objects for InputStream and OutputStream
//and send the data in array to the server via socket
OutputStream outputStream = socket.getOutputStream();
outputStream.write(array, 0, array.length);
Code for Windows Forms app (receiving file)
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[65535];
int bytesRead;
clientStream.Read(message, 0, message.Length);
System.IO.FileStream fs = System.IO.File.Create(path + dt);
//message has been received
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
fs.Write(message, 0, bytesRead);
fs.Close();
Instead of reading the complete array to your memory and sending it to an outputstream afterwards, you could do read/write at the same time, and just use a "small" buffer byte array. Something like this:
public boolean copyStream(InputStream inputStream, OutputStream outputStream){
BufferedInputStream bis = new BufferedInputStream(inputStream);
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
byte[] buffer = new byte[4*1024]; //Whatever buffersize you want to use.
try {
int read;
while ((read = bis.read(buffer)) != -1){
bos.write(buffer, 0, read);
}
bos.flush();
bis.close();
bos.close();
} catch (IOException e) {
//Log, retry, cancel, whatever
return false;
}
return true;
}
on the receiving side you should do the same: Write a portion of bytes as you receive them and not store them completly into the memory befor using.
This might not fix your issue, but is something you should improve anyway.

Socket plain text response cut off

I'm having trouble getting a socket connection between Android(client) and a c# app(server) to read a response correctly.
I've successfully got a message sending from android to c#, and I'm reading it fine on that end. But when I try to send an acknowledgement back to android, I don't know the correct way to handle this, and I've had to make some assumptions where tutorials have been unclear. I am getting a response back in android, but it's not 100% correct. I've verified via Wireshark that c# is sending what I want it to send, and the text looks fine until it gets to android.
C#:
public void SendClientMessage()
{
NetworkStream clientStream = _Client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Client!"); //Static test message
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
...
Android:
private void listenResponse()
{
Log.i(TAG, "listenRespose() Listening...");
try
{
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int countBytesRead = bis.read(buffer, 0, 8);
String response = new String(buffer);
Log.i(TAG, "listenResponse() Heard: " + response);
}
catch (IOException e)
{
Log.e(TAG, "listenResponse() IOException", e);
e.printStackTrace();
}
Log.i(TAG, "listenResponse() Done Listening.");
}
...
WireShark shows:
Hello Client!
...
Android LogCat shows:
listenRespose() Listening...
listenResponse() Heard: Hello Cl??????????????????????????? [... ?s continue for a long time]
listenResponse() Done Listening.
If instead I initialize my String like this:
String response = new String(buffer, 0, countBytesRead);
I don't get all the question marks at least, but I still don't get the full string I should be getting. Am I initializing my byte[] wrong, or is there a different way to do this better suited for plain text?
You only read 8 bytes here
int countBytesRead = bis.read(buffer, 0, 8);
// max bytes to read ^
instead, read all you can:
int countBytesRead = bis.read(buffer, 0, Buffer.length);
The question marks you see are because your buffer is not initialized.

How to use SSL in TcpClient class

In the .NET framework there is a class TcpClient to retrieve emails from an email server. The TcpClient class has 4 constructors to connect with the server which take at most two parameters. It works fine with those servers which does not use SSL. But gmail or many other email providers use SSL for IMAP.
I can connect with gmail server but can not authenticate with email_id and password.
My code for authenticate user is
public void AuthenticateUser(string username, string password)
{
_imapSw.WriteLine("$ LOGIN " + username + " " + password);
//_imapSw is a object of StreamWriter class
_imapSw.Flush();
Response();
}
But this code can not login.
So how can I use the TcpClient class to retrieve emails when I have to use SSL?
You have to use the SslStream along with the TcpClient then use the SslStream to read the data rather than the TcpClient.
Something along the lines of:
TcpClient mail = new TcpClient();
SslStream sslStream;
mail.Connect("pop.gmail.com", 995);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("pop.gmail.com");
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes != 0);
Console.Write(messageData.ToString());
Console.ReadKey();
EDIT
The above code will simply connect via SSL to Gmail and output the contents of a test message. To log in to a gmail account and issue commands you will need to do something along the lines of:
TcpClient mail = new TcpClient();
SslStream sslStream;
int bytes = -1;
mail.Connect("pop.gmail.com", 995);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("pop.gmail.com");
byte[] buffer = new byte[2048];
// Read the stream to make sure we are connected
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the users login details
sslStream.Write(Encoding.ASCII.GetBytes("USER USER_EMAIL\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the password
sslStream.Write(Encoding.ASCII.GetBytes("PASS USER_PASSWORD\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
// Get the first email
sslStream.Write(Encoding.ASCII.GetBytes("RETR 1\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
Obviously, without all the duplication of code :)
To tailor the best response above specifically to the question of IMAP and IMAP authentication, you will need to modify the code slightly to use IMAP commands as follows. For debugging, you can set breakpoints just after strOut is assigned to view the server responses.
pmOffice pmO = new pmOffice();
pmO.GetpmOffice(3, false);
TcpClient mail = new TcpClient();
SslStream sslStream;
int bytes = -1;
mail.Connect("outlook.office365.com", 993);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("outlook.office365.com");
byte[] buffer = new byte[2048];
// Read the stream to make sure we are connected
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the users login details (insert your username & password in the following line
sslStream.Write(Encoding.ASCII.GetBytes("$ LOGIN " + pmO.mailUsername + " " + pmO.mailPassword + "\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
string strOut = Encoding.ASCII.GetString(buffer, 0, bytes);
// Get the status of the inbox (# of messages)
sslStream.Write(Encoding.ASCII.GetBytes("$ STATUS INBOX (messages)\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
strOut = Encoding.ASCII.GetString(buffer, 0, bytes);
You can wrap the NetworkStream provided by TcpClient with an SslStream. This will provide the necessary handling of SSL and certificates.
You may have to insert some handler code to perform a certificate validation callback, e.g. through ServicePointManager.ServerCertificateValidationCallback.

Categories