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
Add DuplexStream and implement for NetworkStream and QuicStream #51434
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,9 @@ | |
using System.Buffers; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Net.Quic.Implementations.MsQuic.Internal; | ||
using System.Runtime.ExceptionServices; | ||
using System.Runtime.InteropServices; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
@@ -396,10 +398,37 @@ internal override async ValueTask ShutdownWriteCompleted(CancellationToken cance | |
await _state.ShutdownWriteCompletionSource.Task.ConfigureAwait(false); | ||
} | ||
|
||
internal override void Shutdown() | ||
public override void CompleteWrites() | ||
{ | ||
ThrowIfDisposed(); | ||
StartShutdown(QUIC_STREAM_SHUTDOWN_FLAGS.GRACEFUL, errorCode: 0); | ||
try | ||
{ | ||
StartShutdown(QUIC_STREAM_SHUTDOWN_FLAGS.GRACEFUL, errorCode: 0); | ||
} | ||
catch (Exception ex) when (ex is not OutOfMemoryException) | ||
{ | ||
throw new IOException("Unable to complete writes: " + ex.Message, ex); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll do a pass to move all resources into a resx subsequently? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, there's a QUIC issue for it. |
||
} | ||
} | ||
|
||
// We don't wait for QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE event here, | ||
// because it is only sent to us once the peer has acknowledged the shutdown. | ||
// Instead, this method acts more like shutdown(SD_SEND) in that it only "queues" | ||
// the shutdown packet to be sent without any waiting for completion. | ||
public override ValueTask CompleteWritesAsync(CancellationToken cancellationToken) | ||
{ | ||
ThrowIfDisposed(); | ||
if (cancellationToken.IsCancellationRequested) return ValueTask.FromCanceled(cancellationToken); | ||
|
||
try | ||
{ | ||
StartShutdown(QUIC_STREAM_SHUTDOWN_FLAGS.GRACEFUL, errorCode: 0); | ||
return default; | ||
} | ||
catch (Exception ex) when (ex is not OutOfMemoryException) | ||
{ | ||
return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException("Unable to complete writes: " + ex.Message, ex))); | ||
} | ||
} | ||
|
||
// TODO consider removing sync-over-async with blocking calls. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
|
||
namespace System.Net.Quic | ||
{ | ||
public sealed class QuicStream : Stream | ||
public sealed class QuicStream : DuplexStream | ||
{ | ||
private readonly QuicStreamProvider _provider; | ||
|
||
|
@@ -101,7 +101,9 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati | |
|
||
public ValueTask ShutdownWriteCompleted(CancellationToken cancellationToken = default) => _provider.ShutdownWriteCompleted(cancellationToken); | ||
|
||
public void Shutdown() => _provider.Shutdown(); | ||
public override void CompleteWrites() => _provider.CompleteWrites(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we replacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ShutdownWriteCompleted will become something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought that original I don't know anything about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was completely bamboozled by the naming and made assumption based on that. |
||
|
||
public override ValueTask CompleteWritesAsync(CancellationToken cancellationToken = default) => _provider.CompleteWritesAsync(cancellationToken); | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
|
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.
What about a test for calling Write after CompleteWrites?
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.
Also, a test that CompleteWrites implicitly does a Flush? (i.e. call Write without Flush, then CompleteWrites and verify the unflushed data was sent)