Skip to content

Conversation

@wfurt
Copy link
Member

@wfurt wfurt commented Feb 13, 2020

This change primarily fixes a regression caused by #453. In an attempt to not allocate a new buffer for each message we start using _internalBuffer also for the handshake. That unfortunately caused #20507 and #1291

This change brings one buffer used through the entire handshake. The live cycle is managed within ForceAuthenticationAsync() used for both initial handshakes as well as possible renegotiation triggered by reading.

Since ArrayBuffer has convenient APIs, I decided to use it instead of implementing the logic again. This also allowed to complete spanification of SslStream where we have now clean path from ArrayBuffer all the way to native call on all platforms.

I was able to reproduce #1291 on my local systems in ~ 100 runs. So far I did several hundred with this change and I did not see any issue. (aside from flaky DNS)

This change also brings FillHandshakeBufferAsync() very similar to FillBufferAsync.
I think there is opportunity for more refactor but I would like to put out a fix for the failing tests to decrease CI noise for everybody.

fixes #1291
fixes #20507

@wfurt wfurt added this to the 5.0 milestone Feb 13, 2020
@wfurt wfurt requested review from a team and stephentoub February 13, 2020 23:31
@wfurt wfurt self-assigned this Feb 13, 2020
private interface ISslIOAdapter
{
ValueTask<int> ReadAsync(byte[] buffer, int offset, int count);
ValueTask<int> ReadAsync(Memory<byte> buffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need the ValueTask<int> ReadAsync(byte[] buffer, int offset, int count); overload?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used in FillBufferAsync() but that is easy to fix.

if (!receiveFirst)
{
message = _context.NextMessage(reAuthenticationData, 0, (reAuthenticationData == null ? 0 : reAuthenticationData.Length));
message = _context.NextMessage(reAuthenticationData == null ? default : new ReadOnlySpan<byte>(reAuthenticationData));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional shouldn't be necessary, as a null array is converted to a default span by span's ctor/implicit cast/etc.

Suggested change
message = _context.NextMessage(reAuthenticationData == null ? default : new ReadOnlySpan<byte>(reAuthenticationData));
message = _context.NextMessage(reAuthenticationData);

if (reAuthenticationData == null)
{
_nestedAuth = 0;
_handshakeBuffer.Dispose();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we need to dispose this if reAuthenticationData != null? Also, should we set _handshakeBuffer to default after it's been disposed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, we should. I missed that part.

int version = -1;

if ((bytes == null || bytes.Length <= 0))
if (bytes.Length <= 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll never be < 0.

Suggested change
if (bytes.Length <= 0)
if (bytes.Length == 0)

@wfurt wfurt merged commit f5874b0 into dotnet:master Feb 14, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 10, 2020
@wfurt wfurt deleted the sslBuffers branch January 7, 2026 19:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

2 participants