Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read with timeout is incompatible with SslStream #1501

Closed
roji opened this issue Mar 19, 2017 · 22 comments
Closed

Read with timeout is incompatible with SslStream #1501

roji opened this issue Mar 19, 2017 · 22 comments
Assignees
Labels
Milestone

Comments

@roji
Copy link
Member

roji commented Mar 19, 2017

As @Emill wrote in gitter, our current synchronous implementation of Wait() will fail if a timeout is passed and SslStream is used, because:

SslStream assumes that a timeout along with any other IOException when one is thrown from the inner stream will be treated as fatal by its caller. Reusing a SslStream instance after a timeout will return garbage. An application should Close the SslStream and throw an exception in these cases.

See http://stackoverflow.com/questions/37177401/how-to-repeatedly-read-from-net-sslstream-with-a-timeout.

Note sure if there's a good workaround for SslStream. For now, adding a check that throws NotSupportedException.

@roji roji added the bug label Mar 19, 2017
@roji roji assigned Emill and roji Mar 19, 2017
roji added a commit that referenced this issue Mar 19, 2017
@roji roji added this to the Backlog milestone Jun 8, 2018
cladisch added a commit to cladisch/npgsql that referenced this issue Mar 9, 2020
roji pushed a commit that referenced this issue Mar 10, 2020
roji pushed a commit that referenced this issue Mar 10, 2020
@YohDeadfall
Copy link
Contributor

@vonzshik since you're working with timeouts, you cant take a look at this. Otherwise, I could take this a bit later since already did some SSL stuff.

@vonzshik
Copy link
Contributor

@YohDeadfall sure I can take a look - but doesn't it mean, that ReadBuffer has the same problem?

@YohDeadfall
Copy link
Contributor

Yes, it has. The buffer is just a wrapper around the stream.

@vonzshik
Copy link
Contributor

Interestingly enough, it seems to work fine for .net 5, but not for .net 4.6.1

@YohDeadfall
Copy link
Contributor

Oh, very good! If it also works for .NET 3.1 we could just close this issue because .NET Framework is on the way to a graveyard.

@roji
Copy link
Member Author

roji commented Sep 24, 2020

You mean that SslStream actually works well with timeouts now? BTW I assume we're discussing sync timeouts, I wonder if async ones (via cancellation tokens) work?

Related (but the outcome of that issue isn't clear): dotnet/runtime#22496

@roji
Copy link
Member Author

roji commented Sep 24, 2020

Oh, very good! If it also works for .NET 3.1 we could just close this issue because .NET Framework is on the way to a graveyard.

I think we can just conditional-compile the check to only throw for TFMs where the timeout doesn't work (i.e. net461).

@roji
Copy link
Member Author

roji commented Sep 24, 2020

I would also assume that it doesn't work on .NET Core 3.1 because of dotnet/runtime#22496

@vonzshik
Copy link
Contributor

I would also assume that it doesn't work on .NET Core 3.1 because of dotnet/runtime#22496

It actually does work - results.

[Test]
public void WaitWithSsl()
{
	var csb = new NpgsqlConnectionStringBuilder(ConnectionString)
	{
		SslMode = SslMode.Require,
		TrustServerCertificate = true,
	};
	using (var conn = OpenConnection(csb.ToString()))
	{
		conn.ExecuteNonQuery("LISTEN notifytest");
		Assert.That(conn.Wait(1000), Is.EqualTo(false));
		Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
	}
}

@roji
Copy link
Member Author

roji commented Sep 24, 2020

Well then... great! So I guess just conditionally-compile the check for net461?

@roji
Copy link
Member Author

roji commented Sep 24, 2020

(Technically there's also 2.x, with 2.1 being still supported. We can check what's going on there if we want to be complete)

@vonzshik
Copy link
Contributor

You mean that SslStream actually works well with timeouts now? BTW I assume we're discussing sync timeouts, I wonder if async ones (via cancellation tokens) work?

Nope for async ones, as .net 4.6.1 doesn't support the cancellation on the socket level through the cancellation token.

@roji
Copy link
Member Author

roji commented Sep 24, 2020

Right, but maybe SslStream does support cancellation tokens in .NET 5.0, just like they improved NetworkStream to do it?

@vonzshik
Copy link
Contributor

I'm not sure how it would help. The problem is, SslStream (and maybe NetworkStream, have not checked yet) uses default implementation from Stream for async methods. And this implementation flatly ignores the cancellation token you supply (.net 4.8).

@roji
Copy link
Member Author

roji commented Sep 24, 2020

NetworkStream definitely does honor cancellation tokens (see dotnet/corefx#36516), otherwise this whole work we're doing would have been for nothing :)

SslStream also seems to flow cancellation tokens, and so maybe honors them too (see ReadAsync, and then this. We can test this to be sure.

@vonzshik
Copy link
Contributor

@roji I'm talking about .net 4.6.1, not .net core. AFAIK, it still uses the same libraries from .net 4.6.1.

@vonzshik
Copy link
Contributor

And that is why every test with the cancellation token is disabled for .net 4.6.1 - they would be stuck forever.

@vonzshik
Copy link
Contributor

vonzshik commented Sep 24, 2020

Also, wouldn't it in case of ,net standard 2.0 and 2.1 be entirely dependent on runtime?

@roji
Copy link
Member Author

roji commented Sep 24, 2020

@roji I'm talking about .net 4.6.1, not .net core. AFAIK, it still uses the same libraries from .net 4.6.1.

Ah OK, I misunderstood.

And that is why every test with the cancellation token is disabled for .net 4.6.1 - they would be stuck forever.

For sync Wait, we've been throwing up to now if a timeout is specified but the connection is secure. I was proposing that if we keep that behavior but only for .NET 4.6.1, the test could test it (i.e. that we throw in those conditions). In other words, instead of not have the test at all for NET461, we could have a version that asserts that we throw the right exception. If we do this, I think it makes sense to also do the same for async.

Also, wouldn't it in case of ,net standard 2.0 and 2.1 be entirely dependent on runtime?

Good point - we indeed shouldn't go into differentiating .NET Framework from .NET Core at runtime.

@vonzshik
Copy link
Contributor

vonzshik commented Sep 25, 2020

For sync Wait, we've been throwing up to now if a timeout is specified but the connection is secure. I was proposing that if we keep that behavior but only for .NET 4.6.1, the test could test it (i.e. that we throw in those conditions). In other words, instead of not have the test at all for NET461, we could have a version that asserts that we throw the right exception. If we do this, I think it makes sense to also do the same for async.

And I've also misunderstood 😄.
The only problem I see is .net standard 2.0, which can be used together with .net 4.6.1 and .net core 2.0. I suppose, there is nothing really we can do.

@roji
Copy link
Member Author

roji commented Sep 25, 2020

I agree. We can just let it do the timeout on netstandard2.0 (i.e. not block it), and if the user is on .NET Framework it's their problem...

@NinoFloris
Copy link
Member

This sounds like a problem that will slowly fade away on its own. We also haven't gotten many new issues around this, closing.

@NinoFloris NinoFloris closed this as not planned Won't fix, can't repro, duplicate, stale Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants