xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/web_transport/web_transport.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This header contains interfaces that abstract away different backing
6 // protocols for WebTransport.
7 
8 #ifndef QUICHE_WEB_TRANSPORT_WEB_TRANSPORT_H_
9 #define QUICHE_WEB_TRANSPORT_WEB_TRANSPORT_H_
10 
11 #include <cstddef>
12 #include <cstdint>
13 #include <memory>
14 #include <string>
15 
16 // The dependencies of this API should be kept minimal and independent of
17 // specific transport implementations.
18 #include "absl/strings/string_view.h"
19 #include "absl/time/time.h"
20 #include "absl/types/span.h"
21 #include "quiche/common/platform/api/quiche_export.h"
22 #include "quiche/common/quiche_callbacks.h"
23 #include "quiche/common/quiche_stream.h"
24 
25 namespace webtransport {
26 
27 enum class Perspective { kClient, kServer };
28 
29 // A numeric ID uniquely identifying a WebTransport stream. Note that by design,
30 // those IDs are not available in the Web API, and the IDs do not necessarily
31 // match between client and server perspective, since there may be a proxy
32 // between them.
33 using StreamId = uint32_t;
34 // Application-specific error code used for resetting either the read or the
35 // write half of the stream.
36 using StreamErrorCode = uint32_t;
37 // Application-specific error code used for closing a WebTransport session.
38 using SessionErrorCode = uint32_t;
39 
40 // WebTransport priority as defined in
41 // https://w3c.github.io/webtransport/#webtransportsendstream-write
42 // The rules are as follows:
43 // - Streams with the same priority are handled in FIFO order.
44 // - Streams with the same group_id but different send_order are handled
45 //   strictly in order.
46 // - Different group_ids are handled in the FIFO order.
47 using SendGroupId = uint32_t;
48 using SendOrder = int64_t;
49 struct QUICHE_EXPORT StreamPriority {
50   SendGroupId send_group_id = 0;
51   SendOrder send_order = 0;
52 
53   bool operator==(const StreamPriority& other) const {
54     return send_group_id == other.send_group_id &&
55            send_order == other.send_order;
56   }
57 };
58 
59 // An outcome of a datagram send call.
60 enum class DatagramStatusCode {
61   // Datagram has been successfully sent or placed into the datagram queue.
62   kSuccess,
63   // Datagram has not been sent since the underlying QUIC connection is blocked
64   // by the congestion control.  Note that this can only happen if the queue is
65   // full.
66   kBlocked,
67   // Datagram has not been sent since it is too large to fit into a single
68   // UDP packet.
69   kTooBig,
70   // An unspecified internal error.
71   kInternalError,
72 };
73 
74 // An outcome of a datagram send call, in both enum and human-readable form.
75 struct QUICHE_EXPORT DatagramStatus {
DatagramStatusDatagramStatus76   explicit DatagramStatus(DatagramStatusCode code, std::string error_message)
77       : code(code), error_message(std::move(error_message)) {}
78 
79   DatagramStatusCode code;
80   std::string error_message;
81 };
82 
83 enum class StreamType {
84   kUnidirectional,
85   kBidirectional,
86 };
87 
88 // Based on
89 // https://w3c.github.io/webtransport/#dictdef-webtransportdatagramstats.
90 struct QUICHE_EXPORT DatagramStats {
91   uint64_t expired_outgoing;
92   uint64_t lost_outgoing;
93 
94   // droppedIncoming is not present, since in the C++ API, we immediately
95   // deliver datagrams via callback, meaning there is no queue where things
96   // would be dropped.
97 };
98 
99 // Based on https://w3c.github.io/webtransport/#web-transport-stats
100 // Note that this is currently not a complete implementation of that API, as
101 // some of those still need to be clarified in
102 // https://github.com/w3c/webtransport/issues/537
103 struct QUICHE_EXPORT SessionStats {
104   absl::Duration min_rtt;
105   absl::Duration smoothed_rtt;
106   absl::Duration rtt_variation;
107 
108   uint64_t estimated_send_rate_bps;  // In bits per second.
109 
110   DatagramStats datagram_stats;
111 };
112 
113 // The stream visitor is an application-provided object that gets notified about
114 // events related to a WebTransport stream.  The visitor object is owned by the
115 // stream itself, meaning that if the stream is ever fully closed, the visitor
116 // will be garbage-collected.
117 class QUICHE_EXPORT StreamVisitor : public quiche::ReadStreamVisitor,
118                                     public quiche::WriteStreamVisitor {
119  public:
~StreamVisitor()120   virtual ~StreamVisitor() {}
121 
122   // Called when RESET_STREAM is received for the stream.
123   virtual void OnResetStreamReceived(StreamErrorCode error) = 0;
124   // Called when STOP_SENDING is received for the stream.
125   virtual void OnStopSendingReceived(StreamErrorCode error) = 0;
126   // Called when the write side of the stream is closed and all of the data sent
127   // has been acknowledged ("Data Recvd" state of RFC 9000).  Primarily used by
128   // the state machine of the Web API.
129   virtual void OnWriteSideInDataRecvdState() = 0;
130 };
131 
132 // A stream (either bidirectional or unidirectional) that is contained within a
133 // WebTransport session.
134 class QUICHE_EXPORT Stream : public quiche::ReadStream,
135                              public quiche::WriteStream,
136                              public quiche::TerminableStream {
137  public:
~Stream()138   virtual ~Stream() {}
139 
140   // An ID that is unique within the session.  Those are not exposed to the user
141   // via the web API, but can be used internally for bookkeeping and
142   // diagnostics.
143   virtual StreamId GetStreamId() const = 0;
144 
145   // Resets the read or the write side of the stream with the specified error
146   // code.
147   virtual void ResetWithUserCode(StreamErrorCode error) = 0;
148   virtual void SendStopSending(StreamErrorCode error) = 0;
149 
150   // A general-purpose stream reset method that may be used when a specific
151   // error code is not available.
152   virtual void ResetDueToInternalError() = 0;
153   // If the stream has not been already reset, reset the stream. This is
154   // primarily used in the JavaScript API when the stream object has been
155   // garbage collected.
156   virtual void MaybeResetDueToStreamObjectGone() = 0;
157 
158   virtual StreamVisitor* visitor() = 0;
159   virtual void SetVisitor(std::unique_ptr<StreamVisitor> visitor) = 0;
160 };
161 
162 // Visitor that gets notified about events related to a WebTransport session.
163 class QUICHE_EXPORT SessionVisitor {
164  public:
~SessionVisitor()165   virtual ~SessionVisitor() {}
166 
167   // Notifies the visitor when the session is ready to exchange application
168   // data.
169   virtual void OnSessionReady() = 0;
170 
171   // Notifies the visitor when the session has been closed.
172   virtual void OnSessionClosed(SessionErrorCode error_code,
173                                const std::string& error_message) = 0;
174 
175   // Notifies the visitor when a new stream has been received.  The stream in
176   // question can be retrieved using AcceptIncomingBidirectionalStream() or
177   // AcceptIncomingUnidirectionalStream().
178   virtual void OnIncomingBidirectionalStreamAvailable() = 0;
179   virtual void OnIncomingUnidirectionalStreamAvailable() = 0;
180 
181   // Notifies the visitor when a new datagram has been received.
182   virtual void OnDatagramReceived(absl::string_view datagram) = 0;
183 
184   // Notifies the visitor that a new outgoing stream can now be created.
185   virtual void OnCanCreateNewOutgoingBidirectionalStream() = 0;
186   virtual void OnCanCreateNewOutgoingUnidirectionalStream() = 0;
187 };
188 
189 // An abstract interface for a WebTransport session.
190 //
191 // *** AN IMPORTANT NOTE ABOUT STREAM LIFETIMES ***
192 // Stream objects are managed internally by the underlying QUIC stack, and can
193 // go away at any time due to the peer resetting the stream. Because of that,
194 // any pointers to the stream objects returned by this class MUST NEVER be
195 // retained long-term, except inside the stream visitor (the stream visitor is
196 // owned by the stream object). If you need to store a reference to a stream,
197 // consider one of the two following options:
198 //   (1) store a stream ID,
199 //   (2) store a weak pointer to the stream visitor, and then access the stream
200 //       via the said visitor (the visitor is guaranteed to be alive as long as
201 //       the stream is alive).
202 class QUICHE_EXPORT Session {
203  public:
~Session()204   virtual ~Session() {}
205 
206   // Closes the WebTransport session in question with the specified |error_code|
207   // and |error_message|.
208   virtual void CloseSession(SessionErrorCode error_code,
209                             absl::string_view error_message) = 0;
210 
211   // Return the earliest incoming stream that has been received by the session
212   // but has not been accepted.  Returns nullptr if there are no incoming
213   // streams.  See the class note regarding the lifetime of the returned stream
214   // object.
215   virtual Stream* AcceptIncomingBidirectionalStream() = 0;
216   virtual Stream* AcceptIncomingUnidirectionalStream() = 0;
217 
218   // Returns true if flow control allows opening a new stream.
219   //
220   // IMPORTANT: See the class note regarding the lifetime of the returned stream
221   // object.
222   virtual bool CanOpenNextOutgoingBidirectionalStream() = 0;
223   virtual bool CanOpenNextOutgoingUnidirectionalStream() = 0;
224 
225   // Opens a new WebTransport stream, or returns nullptr if that is not possible
226   // due to flow control.  See the class note regarding the lifetime of the
227   // returned stream object.
228   //
229   // IMPORTANT: See the class note regarding the lifetime of the returned stream
230   // object.
231   virtual Stream* OpenOutgoingBidirectionalStream() = 0;
232   virtual Stream* OpenOutgoingUnidirectionalStream() = 0;
233 
234   // Returns the WebTransport stream with the corresponding ID.
235   //
236   // IMPORTANT: See the class note regarding the lifetime of the returned stream
237   // object.
238   virtual Stream* GetStreamById(StreamId id) = 0;
239 
240   virtual DatagramStatus SendOrQueueDatagram(absl::string_view datagram) = 0;
241   // Returns a conservative estimate of the largest datagram size that the
242   // session would be able to send.
243   virtual uint64_t GetMaxDatagramSize() const = 0;
244   // Sets the largest duration that a datagram can spend in the queue before
245   // being silently dropped.
246   virtual void SetDatagramMaxTimeInQueue(absl::Duration max_time_in_queue) = 0;
247 
248   // Returns stats that generally follow the semantics of W3C WebTransport API.
249   virtual DatagramStats GetDatagramStats() = 0;
250   virtual SessionStats GetSessionStats() = 0;
251 
252   // Sends a DRAIN_WEBTRANSPORT_SESSION capsule or an equivalent signal to the
253   // peer indicating that the session is draining.
254   virtual void NotifySessionDraining() = 0;
255   // Notifies that either the session itself (DRAIN_WEBTRANSPORT_SESSION
256   // capsule), or the underlying connection (HTTP GOAWAY) is being drained by
257   // the peer.
258   virtual void SetOnDraining(quiche::SingleUseCallback<void()> callback) = 0;
259 };
260 
261 }  // namespace webtransport
262 
263 #endif  // QUICHE_WEB_TRANSPORT_WEB_TRANSPORT_H_
264