Bug 30064 - SslStream ReadTimeout does not work
Summary: SslStream ReadTimeout does not work
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System ()
Version: 4.0.0
Hardware: All All
: --- normal
Target Milestone: Untriaged
Assignee: Martin Baulig
URL:
Depends on:
Blocks:
 
Reported: 2015-05-14 03:32 UTC by RogerH
Modified: 2017-09-13 19:03 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description RogerH 2015-05-14 03:32:23 UTC
Summary
-------
Mono does not support the ReadTimeout on an SslStream. A Read() will block forever and not time out.

Details
-------
The ReadTimeout property of SslStream is designed to be used with a blocking Read(). If no data has been received on the SslStream after the ReadTimeout period, a IOException error should be thrown.

On Windows .Net 4.5 this happens.

On Mono no exception is thrown and the Read() blocks forever.
Setting the ReadTimeout in the inner stream (from TcpClient.getStream() ) before wrapping it with SslStream has no effect. I suspect SslStream is consuming and ignoring any timeout exceptions from the inner stream (from the TCP socket)

Platforms Tested
----------------
Tested with Mono 4.0.1
I first spotted the bug with Xamarin.iOS while developing an iOS app.
Then confirmed it also happens on Mono for Windows (Mono 4.0.1 on Win8.1) and Mono for Mac (Mono 4.0.1 on OSX 10.10) with the test code below.
On Windows and Mac I use mozroots to import certificates




Test Code
---------
The following code should connect to www.microsoft.com and try and Read(). There will be nothing to read as we are not sending a HTTP request. What should happen is after 500ms the Read() should Timeout and throw an exception.
(This is what happens on .Net on a Windows machine).
Mono blocks on the read, and eventually exits when Microsoft's web server closes the socket after about 15 seconds.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            // Perform test code
            Test_SSL_ReadTimeout();
        }


        static void Test_SSL_ReadTimeout()
        {
            String host = "www.microsoft.com";
            int    port = 443;
            TcpClient client = new TcpClient(host,port);

            Console.WriteLine("Connected");

            SslStream sslstream = new SslStream(client.GetStream(), leaveInnerStreamOpen: false);

            sslstream.AuthenticateAsClient(host);

            Console.WriteLine("Authenticated");

            try
            {
                sslstream.ReadTimeout = 500;
                int next_byte = sslstream.ReadByte();
                if (next_byte != -1) Console.WriteLine("Received byte " + next_byte);
            }
            catch (System.IO.IOException e) {
                Console.WriteLine("IO Exception");
            }



            Console.WriteLine("Press ENTER to quit");
            Console.ReadLine();

        }
    }
}
Comment 1 gerardo.trotta 2017-06-05 16:59:02 UTC
Confirmed on MONO for Linux, Broadcom BCM2837, 4× ARM Cortex-A53, 1.2GHz, MONO 5.0.1.1.

Code:
if (secure)
{
                this.netStream = new NetworkStream(this.socket);
                this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);

                this.sslStream.WriteTimeout = 45000;
                this.sslStream.ReadTimeout = 45000;
....
}



        /// <summary>
        /// Receive data from the network
        /// </summary>
        /// <param name="buffer">Data buffer for receiving data</param>
        /// <returns>Number of bytes received</returns>
        public int Receive(byte[] buffer)
        {
#if SSL
            if (this.secure)
            {
                // read all data needed (until fill buffer)
                int idx = 0, read = 0;
                while (idx < buffer.Length)
                {
                    read = this.sslStream.Read(buffer, idx, buffer.Length - idx);
                    if (read == 0)
                        return 0;
                    idx += read;
                }
                return buffer.Length;
            }
....
}

this.sslStream.Read timeout after 12/15 minutes.
Comment 2 Martin Baulig 2017-09-13 19:03:02 UTC
Should be fixed.