3

Working on some socket layers using SslStream. reference

Using the reference, I implemented a simple client. The awkward part is when you run the application, it seems the server is not replying to the client.

Going into the debug screen and setting some breakpoints, I realized it was this function that was on an endless loop.

static string ReadMessage(SslStream sslStream)
{
    // Read the  message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker.
    byte [] buffer = new byte[2048];
    StringBuilder messageData = new StringBuilder();
    int bytes = -1;
    do
    {
        bytes = sslStream.Read(buffer, 0, buffer.Length);

        // Use Decoder class to convert from bytes to UTF8 
        // in case a character spans two buffers.
        Decoder decoder = Encoding.UTF8.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer,0,bytes)];
        decoder.GetChars(buffer, 0, bytes, chars,0);
        messageData.Append (chars);
        // Check for EOF. 
        if (messageData.ToString().IndexOf("<EOF>") != -1)
        {
            break;
        }
    } while (bytes != 0); 

    return messageData.ToString();
}

Further investigation pointed out the real criminal here:

bytes = sslStream.Read(buffer, 0, buffer.Length);

Seems like, SslStream.Read() is not returning. Checking the byte[] buffer in debug screen reveals that the response has been written to the buffer till crlf. The function has done it's job, still it's not returning with success?!

What could be the reason for this? What steps should I take to ignore with this issue?

Also, for the skeptical ones: I used openssl to see if the server is behaving as it should, and everything is fine on the server side.

Note: I'm already aware of the SslStream.ReadTimeout property. Though it does the job by raising an exception it is not the right answer for every scenario, specially when server is responding with a large stream of data which can only be read efficiently using a while loop and a buffer.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Derpy Derp
  • 429
  • 1
  • 5
  • 12

3 Answers3

2

I was struggling with the same problem with me, the program was infinite loop.

I solved through the following information

İf you using http,https protocol ? you add to header , "Connection: close\r\n"

Http Standart Article

14.10 Connection

The Connection general-header field allows the sender to specify options that are desired for that particular connection and MUST NOT be communicated by proxies over further connections.

The Connection header has the following grammar:

   Connection = "Connection" ":" 1#(connection-token)
   connection-token  = token

HTTP/1.1 proxies MUST parse the Connection header field before a message is forwarded and, for each connection-token in this field, remove any header field(s) from the message with the same name as the connection-token. Connection options are signaled by the presence of a connection-token in the Connection header field, not by any corresponding additional header field(s), since the additional header field may not be sent if there are no parameters associated with that connection option.

Message headers listed in the Connection header MUST NOT include end-to-end headers, such as Cache-Control.

HTTP/1.1 defines the "close" connection option for the sender to signal that the connection will be closed after completion of the response. For example,

   **Connection: close**

in either the request or the response header fields indicates that the connection SHOULD NOT be considered `persistent' (section 8.1) after the current request/response is complete.

HTTP/1.1 applications that do not support persistent connections MUST include the "close" connection option in every message.

A system receiving an HTTP/1.0 (or lower-version) message that includes a Connection header MUST, for each connection-token in this field, remove and ignore any header field(s) from the message with the same name as the connection-token. This protects against mistaken forwarding of such header fields by pre-HTTP/1.1 proxies. See section 19.6.2.

1

If the connection is still open and the server hasn't written <EOF> then it absolutely makes sense that it's just "hung". It's waiting for more data. The only way it could know there's no more data coming is for the server to have closed the connection.

Has it already managed to read all the data which the server has actually sent? What does messageData look like on the iteration before the call which isn't returning?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • the server has replied sucessfully ending the response with ``. A look into `debug` screen validates that. – Derpy Derp Aug 28 '12 at 14:48
  • 1
    Yes it managed to read all the data till `crlf`. The `messageData` doesn't look like anything because the `.Read()` is stuck, adding a `timeout` reveals that `messageData` contains all the `response` returned by the server. – Derpy Derp Aug 28 '12 at 14:53
-2

After some thinking I figured out a workaround.

sslStream.ReadTimeout = 100; //How much time does it takes for a processor to read and write 2048bytes to the buffer?

Had to use timeout, nothing else seemed to work. Modified the Reader to deal with exceptions.

static string ReadMessage(SslStream sslStream)
{
    // Read the  message sent by the server.
    // The end of the message is signaled using the
    // "<EOF>" marker.
    byte[] buffer = new byte[2048];
    StringBuilder messageData = new StringBuilder();
    int bytes = -1;

    do
    {
        try
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);

        }
        catch (Exception ex)
        {
        }
        // Use Decoder class to convert from bytes to UTF8
        // in case a character spans two buffers.
        Decoder decoder = Encoding.ASCII.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
        decoder.GetChars(buffer, 0, bytes, chars, 0);
        messageData.Append(chars);
        // Check for EOF.
        if (messageData.ToString().IndexOf("\r\n") != -1)
        {
            break;
        }

    }
    while (bytes != -1);



    return messageData.ToString();
}

Though this works, doesn't mean it's a good answer. If someone can provide a better answer, it would be great.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Derpy Derp
  • 429
  • 1
  • 5
  • 12