-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
QUIC Datagram API #53533
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
@karelz seems the bot has trouble adding |
Tagging subscribers to this area: @dotnet/ncl Issue DetailsBackground and MotivationQUIC is finally a proposed standard in RFC, with HTTP/3 and WebTransport on the way. Proposed APInamespace System.Net.Quic
{
public class QuicClientConnectionOptions
{
+ public bool DatagramReceiveEnabled { get { } set { } }
}
+ public delegate void QuicDatagramReceivedEventHandler(object sender, ReadOnlySpan<byte> buffer);
public class QuicConnection
{
+ public bool DatagramReceivedEnabled { get { } set { } }
+ public bool DatagramSendEnabled { get { } set { } }
+ public ushort DatagramMaxSendLength { get { } }
+ public event QuicDatagramReceivedEventHandler? DatagramReceived { add { } remove { } }
+ public ValueTask<bool> SendDatagramAsync(ReadOnlyMemory<byte> buffer, bool priority = false) { }
}
public class QuicListenerOptions
{
+ public bool DatagramReceiveEnabled { get { } set { } }
}
} See wegylexy#1 for implementation with msquic (tested with v1.3.0). Usage Examples// receive
connection.DatagramReceived += (sender, buffer) =>
{
// Parse the readonly span synchronously, without copying all the bytes, into an async task
MyAsyncChannel.Writer.TryWrite(MyZeroCopyHandler.HandleAsync(buffer));
}
// send
var array = ArrayPool<byte>.Shared.Rent(Unsafe.SizeOf<MyTinyStruct>());
try
{
MemoryMarshal.Cast<byte, MyTinyStruct>(array).SetCurrentGameState();
await connection.SendDatagramAsync(array);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
} Alternative DesignsReceiving datagram buffers with a channel (similar to the stream API) was considered, but the msquic datagram buffer is merely a pointer to the underlying UDP buffer such that the buffer content is only available during the event callback. Async handler implies unnecessary cloning of possibly a thousand bytes and increase GC pressure for every single datagram received. Sending with a readonly span was considered for Sending returns a bool to indicate whether the datagram is acknowledged without spurious loss, or throws when discarded/cancelled. Additional API may be added to handle suspected loss. Risks
|
One thing to note about the msquic side of this API is that DatagramMaxSendLength can dynamically change over the course of a connection. It currently can't go down (Although in the future that might change) but it can go up after the connection has been started. Just something to note. |
@ThadHouse If notification is needed, could implement |
I know theres a general rule to not have properties update without user interaction, which is the main reason I brought it up. Not a bug in the implementation, just a note. |
Besides, |
Triage: We will wait for RFC to be finalized (it is not yet to our best knowledge) and for having customer demand. Likely not in 7.0 - perhaps only as preview. @nibanks do you have insights from MsQuic view point on the RFC / customer demand? |
I expect the datagram spec to be RFC by the time 7.0 is released. I have also had a significant number of folks both internal and external, interested in datagram support; but I don't know how many would be using .NET. IMO, I would try really hard to get datagram supported in 7.0. |
I'm using my fork of .NET 6 with msquic 1.8 for datagram. |
Unless the RFC lands by March or earlier, we won't be able to react in time based on this year experience. @wegylexy would you be interested in doing a prototype of the API as mentioned above? (Or we could run it by our API review when it is reasonably close to final shape) ... we might not be ready for that right now, but in couple of months it should be feasible from our side. |
@karelz wegylexy/runtime/.../feature/msquic-datagram is a prototype, forked from a .NET 6 preview when |
HTTP/3 WebTransport will need HTTP Datagram which requires QUIC Datagram. |
Updated to use A prototype is available at https://github.com/wegylexy/quic-with-datagram and a simple WebTransport server prototype on top of that is coming soon. |
WebTransport server prototype: https://github.com/wegylexy/webtransport |
Since the QUIC Datagram extension (https://datatracker.ietf.org/doc/rfc9221/) has been officially released as RFC, is it worth trying to get it in for 7.0? @karelz |
Big +1 to exposing the datagram APIs in .NET. I'd love to see that happen in 7.0. Let me know if you need any help from the MsQuic side. |
Given the load on the team and our capacity, I don't think we will be able to do anything meaningful in 7.0. |
Some interesting pieces from the RFC to consider during design:
=> We need to allow user code to decide whether the connection is aborted when Datagram support is absent
This is probably what ThadHouse meant when he said that the maximum datagram send size can change during the lifetime of the connection.
So far we don't have any way to express prioritization of QuicStreams, so not sure how we would fit Datagrams in the scheme. @nibanks does MsQuic support stream/datagram prioritization?
Putting here just to note that notifying user about datagram loss is not strictly required by the RFC. |
We have the
Correct.
For Streams, we have
We already have a notification for indicating loss, as a part of typedef enum QUIC_DATAGRAM_SEND_STATE {
QUIC_DATAGRAM_SEND_UNKNOWN, // Not yet sent.
QUIC_DATAGRAM_SEND_SENT, // Sent and awaiting acknowledegment
QUIC_DATAGRAM_SEND_LOST_SUSPECT, // Suspected as lost, but still tracked
QUIC_DATAGRAM_SEND_LOST_DISCARDED, // Lost and not longer being tracked
QUIC_DATAGRAM_SEND_ACKNOWLEDGED, // Acknowledged
QUIC_DATAGRAM_SEND_ACKNOWLEDGED_SPURIOUS, // Acknowledged after being suspected lost
QUIC_DATAGRAM_SEND_CANCELED, // Canceled before send
} QUIC_DATAGRAM_SEND_STATE; |
|
Rebased my sample implementation onto .NET 7.0 wegylexy@d4abf8e |
The allocations implied by these APIs seem likely to be unacceptable to a lot of potential users. The |
How about this? public class DatagramSendOptions
{
bool Priority { get { throw null; } set { } }
Action? Sent { get { throw null; } set { } }
Action? LostSuspect { get { throw null; } set { } }
Action? Lost { get { throw null; } set { } }
Action? Acknowledged { get { throw null; } set { } }
}
public Task SendDatagramAsync(ReadOnlyMemory<byte> buffer, DatagramSendOptions options = null);
public Task SendDatagramAsync(ReadOnlySequence<byte> buffer, DatagramSendOptions options = null); When the task completes, it will be safe to release the buffer. |
Edited proposed API just now to eliminate Task allocations for sending a datagram. |
Can anyone review the above for integration and give any feedback? I have significant interest in this and am willing to help. It looks like @wegylexy has done significant work and presently this appears to be on a "sometime in the future" milestone. Seems like an easy integration with high value for next release. |
I don't speak for the whole networking team, but I am interested in this feature as well. We really wanted to take this in 8.0, but we were a bit short-staffed and had to cut some features. We will probably have enough bandwidth to work on this in 9.0 timeframe. |
Related: microsoft/msquic#3906 |
Background and Motivation
QUIC is finally a proposed standard in RFC, with HTTP/3 and WebTransport on the way.
To prepare for WebTransport and other use cases, such as unreliable message delivery in SignalR, .NET should implement QUIC datagram API, as MsQuic already supports it, to enable higher-level APIs such as WebTransport.
Until WebTransport is standardized, it may be used today to stream real-time game state and ultra low-latency voice data where dropped packets should not be retransmitted. Once this is done, SignalR may also support new features.
Proposed API
See https://github.com/wegylexy/quic-with-datagram for implementation (with MsQuic 1.9.0).
Usage Examples
Alternative Designs
Receiving datagram buffers with a channel (similar to the stream API) was considered, but the MsQuic datagram buffer is merely a pointer to the underlying UDP buffer such that the buffer content is only available during the event callback. Async handler implies unnecessary cloning of possibly a thousand bytes and increase GC pressure for every single datagram received.
Sending with a readonly span was considered for
stackalloc
ed buffer, but MsQuic needs to hold on to the memory until the datagram send state becomes final.The text was updated successfully, but these errors were encountered: