[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[QUIC] API QuicStream - #71969

Merged
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream
Jul 13, 2022
Merged

[QUIC] API QuicStream#71969
ManickaP merged 18 commits into
dotnet:mainfrom
ManickaP:mapichov/quic-stream

Conversation

@ManickaP

@ManickaPManickaP commented Jul 11, 2022

Copy link
Copy Markdown
Member

Fixes#69675

This PR is based on #71783 so it shows more changes than it actually contains, see https://github.com/ManickaP/runtime/compare/mapichov/quic-connection...ManickaP:runtime:mapichov/quic-stream?expand=1 for the actual diff.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #69675

This PR is based on #71783 so it shows more changes than it actually contains.

ATM depends on: microsoft/msquic#2883 but AFAIK only one outerloop test is failing because of this (the one testing stream shutdown due to idle connection). Depending on severity of this and speed on that msquic PR, I may temporarily re-introduce connection state from:

// TODO: remove once/if https://github.com/microsoft/msquic/pull/2872 is merged
internalsealedclassState
{
publiclongAbortErrorCode=-1;
}
privateState_state=newState();

Also I'll be filling in comments, not everything is covered.

Kept in draft until API is approved.

Author:ManickaP
Assignees:-
Labels:

new-api-needs-documentation, area-System.Net.Quic

Milestone:-

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this inside do...while ? One iteration can copy, and the following can throw?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The loop can iterate at most twice. First, it tries to copy from the buffer, if it succeeds (data are already there) it will break out of the loop in while (... totalCopied == 0);. If no data are available in the buffer, the await valueTask.ConfigureAwait(false); will wait on the next RECEIVE event and once it arrives it will repeat the loop with copying, copy something (or learn about FIN flag) and break out of the loop.

The valueTask must be awaited each time it's retrieved, even if it's completed and it seems pointless - e.g.: _receiveTcs.TrySetResult();, since it's backed up by MRVTS which keeps "version" and the await will reset it (increment it).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don't understand how we would overcome the race when - between the first and the second iteration - a parallel read could come and "steal" the arrived data? What would happen to the first read? It seems like it could either throw or - would it start waiting on data to arrive again?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we make sure send buffers are not disposed in the middle of send operation?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

By awaiting the valueTask above which waits on SHUTDOWN_COMPLETE which is the last event on the stream and means both side are closed, so no send operation is in progress.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Added comment 3 lines above, at the valueTask await.

@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch 3 times, most recently from ac8f5ca to ecd1e28CompareJuly 12, 2022 20:43
@ManickaP
ManickaPforce-pushed the mapichov/quic-stream branch from 851251d to d1337e9CompareJuly 13, 2022 07:36
Comment threadsrc/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs Outdated
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We no longer do the ShutdownCompleted because we expect that in Dispose? Is there reason to delay that if we know this is final?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Delay what exactly? DisposeAsync is controlled from the calling code. In most cases the tests are just doing this:

awaitusingHttp3LoopbackStreamstream=awaitconnection.AcceptRequestStreamAsync();awaitstream.HandleRequestAsync();

And in some cases, the tests are playing with postponing the disposal to later, doing cancellations etc.

Potentially we could replace it with await Task.WhenAll(_stream.WritesClosed, _stream.ReadsClosed); which should correspond to SHUTDOWN_COMPLETE give or take. But I haven't experience any issues with the state as-is in this PR, so I don't particularly see reason to change it. After all, this (meaning as-is now) will be usage pattern done by the lib consumers.

@wfurtwfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally looks ok to me. I wish we have better names for some of the handles but that is ok.
It seems like we also break the build/tests in few places and that should be fixed before merging.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good modulo existing comments

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs Outdated
_abortErrorCode = (long)data.ErrorCode;
_state.AbortErrorCode = _abortErrorCode;
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException(_abortErrorCode)));
_acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we store the error code anywhere? it might be useful during dump investigation.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It'll stay set in the Exception in the _acceptQueue, so it's available, although less conveniently. Do you want me to reintroduce it? Is it something you used while doing investigations?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A comment like "this will loop at most twice" would be nice :)

Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated
Comment threadsrc/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment for this please? This is something I am going to forget very soon :D

Comment threadsrc/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs Outdated
@ManickaP

Copy link
Copy Markdown
MemberAuthor

All comments should be answered, only waiting on CI.

await valueTask.ConfigureAwait(false);

// This is the last read, finish even despite not copying anything.
if (complete)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do I understand correctly, that complete can only become true in "synchronous" case? Meaning, we didn't actually wait for anything in valueTask above

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, but I'd formulate it differently: if complete was reported as true then the valueTask will complete synchronously. Note that the valueTask might have been completed (whether temporarily or finally) before it got to _receiveTcs.TrySetResult(final: true);.

@ManickaP

Copy link
Copy Markdown
MemberAuthor

One failure unrelated: #71233
One failure related (windows), reproduced locally, fixed and tested locally in a tight loop.
--> Merging now.

@ManickaP
ManickaP merged commit af43652 into dotnet:mainJul 13, 2022
@ManickaP
ManickaP deleted the mapichov/quic-stream branch July 13, 2022 18:02
ManickaP added a commit to ManickaP/runtime that referenced this pull request Jul 13, 2022
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
@ManickaP

Copy link
Copy Markdown
MemberAuthor

@JamesNK this will need your reaction as well. This contains the stream changes, most interesting will be the ReadsClosed, WritesClosed tasks.

carlossanlop pushed a commit that referenced this pull request Jul 13, 2022
…72031) (#72106)
* [QUIC] API QuicConnection (#71783)
* Listener comment; PreviewFeature attribute
* Feedback
* QuicConnection new API including compilable implementation
* Fixed logging
* Fixed S.N.Quic and S.N.Http tests
* Options now correspond to the issue
* Feedback
* Comments, PreviewFeature attribute and RemoteCertificate disposal.
* Preview feature attribute is assembly wide
* Some typos
* Fixed test with certificate
* Default values as constants
* Event handlers split into methods called via switch expression.
* Some more comments
* Unified unsafe usage
* Fixed some more tests
* Cleaned up some exceptions and resource strings.
* Feedback
* Latest greatest API proposal.
* Fixed Http solution
* Feedback
* [QUIC] API QuicStream (#71969)
* Quic stream API surface
* Fixed test compilation
* Fixed http test compilation
* HttpLoopbackConnection Dispose -> DisposeAsync
* QuicStream implementation
* Fixed some tests
* Fixed all QUIC and HTTP tests
* Fixed exception type for stream closed by connection close
* Feedback
* Fixed WebSocket.Client test build
* Feedback, test fixes
* Fixed build on framework and windows
* Fixed winhandler test
* Swap variable based on order in defining class
* Post merge fixes
* Feedback and build
* Reverted connection state to pass around abort error code
* Fixed exception type.
* [QUIC] System.Net.Quic API made public (#72031)
* System.Net.Quic removed from ASP transport package and made part of SDK ref
* Removed manual references to System.Net.Quic.csproj
@karelzkarelz added this to the 7.0.0 milestone Jul 19, 2022
@ghostghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: [QUIC] QuicStream

5 participants

@ManickaP@CarnaViire@wfurt@rzikm@karelz