2

I have this loop to read and decode SSL message:

byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
// Works well to this moment
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());

When I debug it I see in "locals" tab that messageData's value is +OK Gpop ready for requests from xxx.xx.xx.xx p49mb48176339eey, but loop doesn't work and message isn't printed to console. Can somebody help me? If u want full code to test, it's here: github.com/WizzieP/MailerPrototype

jww
  • 97,681
  • 90
  • 411
  • 885
  • What does it print? Are you certain that the data in the stream is UTF8 encoded? – Chris Dunaway Jul 11 '14 at 16:12
  • `+OK Gpop ready for requests from xxx.xx.xx.xx p49mb48176339eey` It prints this, as I wrote in my question. Just the loop stops in second iteration and I don't know why. – Andrzej Sołtysik Jul 11 '14 at 17:17
  • When you say "loop stops"-- where does it stop exactly? Is it blocked on the `.Read` call waiting for data? (The message implies that the server is probably waiting for input sent by the client). Keep in mind that you will fail if the 2k block splits a multi-byte character at the end. – EricLaw Jul 11 '14 at 17:34
  • I misunderstood the problem. I thought that something incorrect was being printed. – Chris Dunaway Jul 11 '14 at 22:01

2 Answers2

1

The problem with your code is that a network TCP stream (and thus an SSL stream sitting on top of it) does not ever return 0 from Read() until the connection with the server is closed.

Because of this, you need to use other ways of figuring out if you've read all the data or not.

In your case, since you are trying to read a POP3 server greeting, what you want to do is to keep looping until you've read a "\r\n" sequence (you could also simply check for '\n' as well).

When you go to implement the CAPA, UIDL, STAT, TOP, and RETR commands, you'll want to continue looping until you receive "\r\n.\r\n".

If you would like to see some advanced techniques on how to do this, feel free to browse my code at https://github.com/jstedfast/MailKit/blob/master/MailKit/Net/Pop3/Pop3Stream.cs#L394 (the line # may change, but look for the Read (byte[] buffer, int offset, int count, CancellationToken cancellationToken) method).

What this method does is prevent the consumer of this stream from reading beyond the end of a response to a command such as RETR and TOP. While doing that, it also un-byte-stuffs the data being read from the network (the POP3 server will 'byte-stuff' by prepending a '.' to every line that begins with a '.' in the RETR and TOP responses) so that the consumer can simply read the stream as if it were reading the raw message from disk and not have to worry about handling any of that.

In order to do that, you'll notice that Pop3Stream buffers data. That's what the ReadAhead() method is responsible for.

This is all designed so that I can parse the message more-or-less directly from the socket rather than reading all of the data into 1 big StringBuffer before parsing it: https://github.com/jstedfast/MailKit/blob/master/MailKit/Net/Pop3/Pop3Client.cs#L1275

Between this and the fact that my MIME parser parses the message incrementally (rather than reading the entire message into 1 big StringBuffer) is what makes my code so incredibly fast compared to all of the other .NET POP3 libraries.

Good luck!

jstedfast
  • 35,744
  • 5
  • 97
  • 110
  • I don't know even what's going on in your code on github, I'm only beginner :) But thanks for your answer. – Andrzej Sołtysik Jul 12 '14 at 13:19
  • No problem... and you'll understand it eventually. The important thing is to keep programming and playing with stuff. – jstedfast Jul 12 '14 at 15:41
  • Yeah, I've already realised that :) Can you also help me here?: http://stackoverflow.com/questions/24697937/loop-for-reading-and-decoding-ssl-message-doesnt-work/24712007?noredirect=1#comment38331063_24712007 Becouse when I don't have any visible error or anything like that I don't know how to fix the problem :/ – Andrzej Sołtysik Jul 12 '14 at 15:53
-1

I removed the loop and some code and it worked. I took code in the answer from stackoverflow, so I was suprised it hadn't worked. Here is my new code:

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());