0

I'm trying to determine the number of bytes available to be read so I can read from the SslStream until all data has been read. SslStream doesn't appear to have a property or method to do this so I've been trying to use the underlying Socket. The issue here is that the number of bytes available as reported by the Socket doesn't match the actual amount of decrypted data that I need.

Here is my Receive method:

byte[] Receive()
{
    byte[] messageBuffer = new byte[4096];
    int bytesRead = 0;

    using (var readData = new MemoryStream())
    {
        while(Client.Client.Available > 0)
        {
            bytesRead = Stream.Read(messageBuffer, 0, messageBuffer.Length);
            readData.Write(messageBuffer, 0, bytesRead);
        }

        return readData.ToArray();
    }
} 

Client.Client is the underlying Socket of Stream which is the SslStream. Let's assume a message size of 5000 bytes. There are a couple of issues here:

  1. The first attempt to read Client.Client.Available returns 5077. This is not the correct length of the data available.
  2. After the first call to Stream.Read Client.Client.Available returns 0 so I exit the loop even though I've only read 4096 since that is my buffer size. So there are 904 bytes left on the stream that haven't been read.

So it appears that after I call Stream.Read it removes the entire data from the Socket (all 5000 bytes not just the 4096 I'm asking for), which makes sense because you need the entire message to decrypt it. But there is no way of knowing if you've gotten the entire message then because there is no SslStream.Available or anything of the sort. So my question is how can I tell if I have received the entire decrypted message? (Or how can I get the number of bytes of the decrypted message?)

Other things I have tried:

  • using Client.Client.Poll(someLongTimeoutForTesting, SelectMode.SelectRead) but it returns false after first Stream.Read as well.
  • using Client.GetStream().DataAvailable again returns false after the first Stream.Read
  • increasing the size of the messageBuffer to the max amount Stream.Read will return (16299, not sure why this number but when I increase the message size and buffer size above this Stream.Read() always returns 16299). This method works however it uses an unreasonable amount of memory because in the application it will be used in the client messages are below 4096 99.99% of the time.
CSCoder
  • 154
  • 1
  • 15

2 Answers2

0

If you know length of message, you can read bytes to array and then create stream from this array:

    buffer = new byte[num_of_bytes];
    for (int i = 0; i < num_of_bytes; i++)
        buffer[i] = (byte)sslStream.ReadByte();

    using (var stream = new MemoryStream(buffer))
    {                   
    }
pr3sto
  • 71
  • 1
  • 8
  • I don't know the length of the message, that's precisely what I'm trying to determine. I just used 5000 in my example to demonstrate my problem – CSCoder Oct 27 '16 at 19:24
0

When you work with TCP sockets (streams) you need to implement your own application layer protocol. A very simple solution: you indicate the message size in the first two Bytes (example, it could be the length you decide), you can also allocate one or two Bytes (for example) for the message type, the rest is the payload. So, you know that always the first two Bytes indicate the length so you have to read 2 Bytes. Then you get the payload length. At that moment you know how many Bytes to read. I explain it with more details, not for SslStream but the response is valid also for your case, here: How to read all of Inputstream in Server Socket JAVA

Community
  • 1
  • 1
rodolk
  • 5,606
  • 3
  • 28
  • 34
  • Thanks for the answer! This would be a good solution, however, unfortunately, this is not a option for me because I can't update the client code. I can validate the message I receive matches the expected format so I'm okay with receiving bad/incomplete messages sometimes but my issue is that when the message exceeds the messageBuffer size I never get the correct/complete message. – CSCoder Oct 28 '16 at 17:01