-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement QUIC abort exceptions, fix channel usage, and implement some tests. #32051
Conversation
I was just about to do this 😄
I thought the listener was created once per test still. Did you see this variability? |
…tion, QuicOperationAbortedException. Fix: MsQuic returning null implementation when completing listener/connection channels. Fix: some flags types being defined as 8-bit when they are 32-bit in msquic.h Add some additional tests demonstrating failures seen in HttpClient.
e2a4da7
to
3b93c25
Compare
some http3 code snuck into the commit; fixed now :) |
Yes, xunit test classes are newed up once per test so it wasn't like a race condition. More for organization purposes (I'm worried about unintentionally using it in a way that exercises race conditions VS a specific test -- this is more explicit and in line with how most of our other tests function) |
shouldComplete = true; | ||
} | ||
_sendState = SendState.Aborted; | ||
_sendErrorCode = evt.Data.PeerSendAbort.ErrorCode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sendErrorCode a local variable. I don't believe it is used elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used to throw a QuicStreamAbortedException
on the other side of the ValueTask
@@ -21,11 +21,13 @@ public class MsQuicTests : MsQuicTestBase | |||
[Fact] | |||
public async Task BasicTest() | |||
{ | |||
using QuicListener listener = CreateQuicListener(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is more of a style thing. I personally prefer initialization of the listener in the constructor, but I'm not strongly opposed to making it explicit
} | ||
|
||
if (NetEventSource.IsEnabled) NetEventSource.Exit(this); | ||
|
||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to continue returning null than to throw an exception from AcceptStreamAsync when the connection is closing. The connection being closed is a common enough that throwing an exception feels noisy. I know this will make the QuicConnection.AcceptStreamAsync() wrapper a little more complicated, but I think it's worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, looking back on this, I agree as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that anyone familiar with sockets will expect consistency with that, which is why I went that direction, but I also think most everyone else might expect it will return null. The question becomes who is the more likely user. It's trouble to merge Stream and Socket 🙃.
I don't feel strongly about it. We can change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep it with the "current" behavior of returning null, but fix it in QuicConnection.AcceptStreamAsync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think this needs some more thought now. We should consider how consistent the APIs between QuicStream, QuicConnection, QuicListener need to be in how they behave on disposal. QuicStream.ReadAsync() etc. do not return a nullable type and will need to throw an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to commit this for now to unblock things (the APIs are currently broken, returning null triggers a bug) but will open an issue to figure this out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue: #32142
|
||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should continue returning null here too.
@@ -95,4 +95,8 @@ public class QuicStreamAbortedException : QuicException | |||
public QuicStreamAbortedException(string message, long errorCode) : base(message) { } | |||
public long ErrorCode { get; } | |||
} | |||
public class QuicOperationAbortedException : QuicException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that QuicException derives directly from Exception. Would it be better to have it derive from IOException or possibly OperationCanceledException if it's always user-initiated?
I would lean towards IOException given how it's currently used. I see it's being triggered by stuff like "HandleEventShutdownInitiatedByPeer" which feels really IOExceptiony to me (if it needs to be an exception at all).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea that seems reasonable. Open up an issue for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't know if QuicOperationAbortedException will be necessary now if we start returning null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at SocketException, and it doesn't derive from IOException, so I'm no longer convinced this is the way to go. Maybe it should derive from SystemException (which SocketException does indirectly), but I'm not sure what the guidance there is. Is this supposed to be the base class for all Exceptions in a System.* namespace?
Note regarding the |
@maryamariyan this will be an interesting case as the API is in new library that we intentionally don't ship yet. The API has to go through API iterations and then API review. Then it will be good time to document it once we have final shape. |
New: implement QuicStreamAbortedException, QuicConnectionAbortedException, QuicOperationAbortedException.
Fix: MsQuic returning null implementation when completing listener/connection channels.
Fix: some flags types being defined as 8-bit when they are 32-bit in msquic.h
Reorganize tests a little bit and avoid a shared listener creating variability.
Add some additional tests demonstrating failures seen in HttpClient. Issues created for those: #32050 #32049 #32048