SslStream Read Problem

T

Trecius

Hello, Newsgroupians:

I'm creating an application that will read emails from GMail, using the
System.Net.Sockets.TcpClient and POP protocol. However, I am having a
problem with my SslStream.

After I create the TcpClient, I create my SslStream...

stream = new System.Net.Security.SslStream(tcpclient.GetStream()...);

Now, unlike the MSDN documentation, I cannot read a <EOF>, for the POP
protocol doesn't have this, so I setup my read function as so...

byte[] buffer = new byte[2048];
int nBytesRead;
do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
} while (nBytesRead != 0);

Let's pretend I authenticate, which sends a small message and the server
responds by sending "+OK Gpop ready for requests from 205.219.58.3
23903020fgae.0\r\n"

So, the first time I enter the do statement, it will read those bytes. As
nBytesRead does not equal 0, it will continue the loop. Well, now it tries
to read again, and it just hangs there until it times out.

Well, to alleviate the problem, I put a temporary break in the loop.

do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
break;
} while (nBytesRead != 0);

Well, I can now read the response from GMail's pop server. This, again,
works for small messages. However, if the response from the server is
segmented, I receive only part of the message.

How can I ensure that I receive the entire message? I've tried setting the
stream's .ReadTimeout property and do a try-and-catch, but this method is
incorrect. Can anyone provide me direction into my predicament?

Thank you,


Trecius
 
J

Jon Skeet [C# MVP]

Trecius said:
I'm creating an application that will read emails from GMail, using the
System.Net.Sockets.TcpClient and POP protocol. However, I am having a
problem with my SslStream.

After I create the TcpClient, I create my SslStream...

stream = new System.Net.Security.SslStream(tcpclient.GetStream()...);

Now, unlike the MSDN documentation, I cannot read a <EOF>, for the POP
protocol doesn't have this, so I setup my read function as so...

byte[] buffer = new byte[2048];
int nBytesRead;
do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
} while (nBytesRead != 0);

Let's pretend I authenticate, which sends a small message and the server
responds by sending "+OK Gpop ready for requests from 205.219.58.3
23903020fgae.0\r\n"

So, the first time I enter the do statement, it will read those bytes. As
nBytesRead does not equal 0, it will continue the loop. Well, now it tries
to read again, and it just hangs there until it times out.

Yes, and indeed it should. The server has indicated the end of that
particular response with a "\r\n". It can't close the stream because
you still want to be able to communicate on the same connection. Each
protocol has different ways of handling this sort of conversation flow
- some protocols force each party to say how much data they're going to
write before they do so, and others use delimiters (as is the case
here).
Well, to alleviate the problem, I put a temporary break in the loop.

do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
break;
} while (nBytesRead != 0);

Well, I can now read the response from GMail's pop server. This, again,
works for small messages. However, if the response from the server is
segmented, I receive only part of the message.

How can I ensure that I receive the entire message? I've tried setting the
stream's .ReadTimeout property and do a try-and-catch, but this method is
incorrect. Can anyone provide me direction into my predicament?

Read the POP3 spec carefully to see how to detect the end of responses.
 
T

Trecius

Mr. Skeet:

Just a follow up on your response...

I can see that the last two characters in the message are \r\n. However,
sometimes the response from the server will contain more than one \r\n. For
example, if I RETR <Some Message #> it will more than likely have \r\n in it.

So I cannot use \r\n as the end of file UNLESS it's the last two characters
in the stream. When it partitions the message, will it ensure that the last
two characters are never \r\n unless it's the LAST of the stream?

EXA:

I read 1400 bytes, the last two characters in the stream are a 64 and 72.
Of course I can see many \r\n in the stream, but because the last two bytes
are not \r\n, I should continue to read the stream. In the next stream read
I again can read a lot of \r\n; however, the last two bytes in the stream are
\r\n. As such, this is the last part in the stream.

Am I guaranteed that the message will NOT be divided on a \r\n boundary?


Trecius

Jon Skeet said:
Trecius said:
I'm creating an application that will read emails from GMail, using the
System.Net.Sockets.TcpClient and POP protocol. However, I am having a
problem with my SslStream.

After I create the TcpClient, I create my SslStream...

stream = new System.Net.Security.SslStream(tcpclient.GetStream()...);

Now, unlike the MSDN documentation, I cannot read a <EOF>, for the POP
protocol doesn't have this, so I setup my read function as so...

byte[] buffer = new byte[2048];
int nBytesRead;
do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
} while (nBytesRead != 0);

Let's pretend I authenticate, which sends a small message and the server
responds by sending "+OK Gpop ready for requests from 205.219.58.3
23903020fgae.0\r\n"

So, the first time I enter the do statement, it will read those bytes. As
nBytesRead does not equal 0, it will continue the loop. Well, now it tries
to read again, and it just hangs there until it times out.

Yes, and indeed it should. The server has indicated the end of that
particular response with a "\r\n". It can't close the stream because
you still want to be able to communicate on the same connection. Each
protocol has different ways of handling this sort of conversation flow
- some protocols force each party to say how much data they're going to
write before they do so, and others use delimiters (as is the case
here).
Well, to alleviate the problem, I put a temporary break in the loop.

do
{
nBytesRead = stream.Read(buffer, 0, buffer.Length);
...
break;
} while (nBytesRead != 0);

Well, I can now read the response from GMail's pop server. This, again,
works for small messages. However, if the response from the server is
segmented, I receive only part of the message.

How can I ensure that I receive the entire message? I've tried setting the
stream's .ReadTimeout property and do a try-and-catch, but this method is
incorrect. Can anyone provide me direction into my predicament?

Read the POP3 spec carefully to see how to detect the end of responses.

--
Jon Skeet - <[email protected]>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
 
J

Jon Skeet [C# MVP]

Trecius said:
Just a follow up on your response...

I can see that the last two characters in the message are \r\n. However,
sometimes the response from the server will contain more than one \r\n. For
example, if I RETR <Some Message #> it will more than likely have \r\n in it.

So I cannot use \r\n as the end of file UNLESS it's the last two characters
in the stream. When it partitions the message, will it ensure that the last
two characters are never \r\n unless it's the LAST of the stream?

That depends on the piece of the protocol that you're using at the
time. Messages are terminated with a ".\r\n" (IIRC) whereas other
responses are just single lines.

You should definitely *not* base any decisions on just what *happened*
to be the last two bytes which came down the stream. That could happen
to be a packet boundary, with more data coming. You should work out
whether that "\r\n" actually signals the end of that response or not
based on the protocol.

Again, I urge you to read the POP3 RFC.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top