• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
13 #include <string>
14 
15 // The dependencies of this API should be kept minimal and independent of
16 // specific transport implementations.
17 #include "absl/strings/string_view.h"
18 #include "absl/time/time.h"
19 #include "absl/types/span.h"
20 #include "quiche/common/platform/api/quiche_export.h"
21 #include "quiche/common/quiche_stream.h"
22 #include "quiche/spdy/core/http2_header_block.h"
23 
24 namespace webtransport {
25 
26 // A numeric ID uniquely identifying a WebTransport stream. Note that by design,
27 // those IDs are not available in the Web API, and the IDs do not necessarily
28 // match between client and server perspective, since there may be a proxy
29 // between them.
30 using StreamId = uint32_t;
31 // Application-specific error code used for resetting either the read or the
32 // write half of the stream.
33 using StreamErrorCode = uint8_t;
34 // Application-specific error code used for closing a WebTransport session.
35 using SessionErrorCode = uint32_t;
36 
37 // An outcome of a datagram send call.
38 enum class DatagramStatusCode {
39   // Datagram has been successfully sent or placed into the datagram queue.
40   kSuccess,
41   // Datagram has not been sent since the underlying QUIC connection is blocked
42   // by the congestion control.  Note that this can only happen if the queue is
43   // full.
44   kBlocked,
45   // Datagram has not been sent since it is too large to fit into a single
46   // UDP packet.
47   kTooBig,
48   // An unspecified internal error.
49   kInternalError,
50 };
51 
52 // An outcome of a datagram send call, in both enum and human-readable form.
53 struct QUICHE_EXPORT DatagramStatus {
DatagramStatusDatagramStatus54   explicit DatagramStatus(DatagramStatusCode code, std::string error_message)
55       : code(code), error_message(std::move(error_message)) {}
56 
57   DatagramStatusCode code;
58   std::string error_message;
59 };
60 
61 enum class StreamType {
62   kUnidirectional,
63   kBidirectional,
64 };
65 
66 // The stream visitor is an application-provided object that gets notified about
67 // events related to a WebTransport stream.  The visitor object is owned by the
68 // stream itself, meaning that if the stream is ever fully closed, the visitor
69 // will be garbage-collected.
70 class QUICHE_EXPORT StreamVisitor : public quiche::WriteStreamVisitor {
71  public:
~StreamVisitor()72   virtual ~StreamVisitor() {}
73 
74   // Called whenever the stream has readable data available.
75   virtual void OnCanRead() = 0;
76 
77   // Called when RESET_STREAM is received for the stream.
78   virtual void OnResetStreamReceived(StreamErrorCode error) = 0;
79   // Called when STOP_SENDING is received for the stream.
80   virtual void OnStopSendingReceived(StreamErrorCode error) = 0;
81   // Called when the write side of the stream is closed and all of the data sent
82   // has been acknowledged ("Data Recvd" state of RFC 9000).  Primarily used by
83   // the state machine of the Web API.
84   virtual void OnWriteSideInDataRecvdState() = 0;
85 };
86 
87 // A stream (either bidirectional or unidirectional) that is contained within a
88 // WebTransport session.
89 class QUICHE_EXPORT Stream : public quiche::WriteStream {
90  public:
91   struct QUICHE_EXPORT ReadResult {
92     // Number of bytes actually read.
93     size_t bytes_read;
94     // Whether the FIN has been received; if true, no further data will arrive
95     // on the stream, and the stream object can be soon potentially garbage
96     // collected.
97     bool fin;
98   };
99 
~Stream()100   virtual ~Stream() {}
101 
102   // Reads at most |buffer.size()| bytes into |buffer|.
103   [[nodiscard]] virtual ReadResult Read(absl::Span<char> buffer) = 0;
104   // Reads all available data and appends it to the end of |output|.
105   [[nodiscard]] virtual ReadResult Read(std::string* output) = 0;
106 
107   // Indicates the number of bytes that can be read from the stream.
108   virtual size_t ReadableBytes() const = 0;
109 
110   // An ID that is unique within the session.  Those are not exposed to the user
111   // via the web API, but can be used internally for bookkeeping and
112   // diagnostics.
113   virtual StreamId GetStreamId() const = 0;
114 
115   // Resets the read or the write side of the stream with the specified error
116   // code.
117   virtual void ResetWithUserCode(StreamErrorCode error) = 0;
118   virtual void SendStopSending(StreamErrorCode error) = 0;
119 
120   // A general-purpose stream reset method that may be used when a specific
121   // error code is not available.
122   virtual void ResetDueToInternalError() = 0;
123   // If the stream has not been already reset, reset the stream. This is
124   // primarily used in the JavaScript API when the stream object has been
125   // garbage collected.
126   virtual void MaybeResetDueToStreamObjectGone() = 0;
127 
128   virtual StreamVisitor* visitor() = 0;
129   virtual void SetVisitor(std::unique_ptr<StreamVisitor> visitor) = 0;
130 };
131 
132 // Visitor that gets notified about events related to a WebTransport session.
133 class QUICHE_EXPORT SessionVisitor {
134  public:
~SessionVisitor()135   virtual ~SessionVisitor() {}
136 
137   // Notifies the visitor when the session is ready to exchange application
138   // data.
139   virtual void OnSessionReady(const spdy::Http2HeaderBlock& headers) = 0;
140 
141   // Notifies the visitor when the session has been closed.
142   virtual void OnSessionClosed(SessionErrorCode error_code,
143                                const std::string& error_message) = 0;
144 
145   // Notifies the visitor when a new stream has been received.  The stream in
146   // question can be retrieved using AcceptIncomingBidirectionalStream() or
147   // AcceptIncomingUnidirectionalStream().
148   virtual void OnIncomingBidirectionalStreamAvailable() = 0;
149   virtual void OnIncomingUnidirectionalStreamAvailable() = 0;
150 
151   // Notifies the visitor when a new datagram has been received.
152   virtual void OnDatagramReceived(absl::string_view datagram) = 0;
153 
154   // Notifies the visitor that a new outgoing stream can now be created.
155   virtual void OnCanCreateNewOutgoingBidirectionalStream() = 0;
156   virtual void OnCanCreateNewOutgoingUnidirectionalStream() = 0;
157 };
158 
159 // An abstract interface for a WebTransport session.
160 //
161 // *** AN IMPORTANT NOTE ABOUT STREAM LIFETIMES ***
162 // Stream objects are managed internally by the underlying QUIC stack, and can
163 // go away at any time due to the peer resetting the stream. Because of that,
164 // any pointers to the stream objects returned by this class MUST NEVER be
165 // retained long-term, except inside the stream visitor (the stream visitor is
166 // owned by the stream object). If you need to store a reference to a stream,
167 // consider one of the two following options:
168 //   (1) store a stream ID,
169 //   (2) store a weak pointer to the stream visitor, and then access the stream
170 //       via the said visitor (the visitor is guaranteed to be alive as long as
171 //       the stream is alive).
172 class QUICHE_EXPORT Session {
173  public:
~Session()174   virtual ~Session() {}
175 
176   // Closes the WebTransport session in question with the specified |error_code|
177   // and |error_message|.
178   virtual void CloseSession(SessionErrorCode error_code,
179                             absl::string_view error_message) = 0;
180 
181   // Return the earliest incoming stream that has been received by the session
182   // but has not been accepted.  Returns nullptr if there are no incoming
183   // streams.  See the class note regarding the lifetime of the returned stream
184   // object.
185   virtual Stream* AcceptIncomingBidirectionalStream() = 0;
186   virtual Stream* AcceptIncomingUnidirectionalStream() = 0;
187 
188   // Returns true if flow control allows opening a new stream.
189   //
190   // IMPORTANT: See the class note regarding the lifetime of the returned stream
191   // object.
192   virtual bool CanOpenNextOutgoingBidirectionalStream() = 0;
193   virtual bool CanOpenNextOutgoingUnidirectionalStream() = 0;
194 
195   // Opens a new WebTransport stream, or returns nullptr if that is not possible
196   // due to flow control.  See the class note regarding the lifetime of the
197   // returned stream object.
198   //
199   // IMPORTANT: See the class note regarding the lifetime of the returned stream
200   // object.
201   virtual Stream* OpenOutgoingBidirectionalStream() = 0;
202   virtual Stream* OpenOutgoingUnidirectionalStream() = 0;
203 
204   // Returns the WebTransport stream with the corresponding ID.
205   //
206   // IMPORTANT: See the class note regarding the lifetime of the returned stream
207   // object.
208   virtual Stream* GetStreamById(StreamId id) = 0;
209 
210   virtual DatagramStatus SendOrQueueDatagram(absl::string_view datagram) = 0;
211   // Returns a conservative estimate of the largest datagram size that the
212   // session would be able to send.
213   virtual uint64_t GetMaxDatagramSize() const = 0;
214   // Sets the largest duration that a datagram can spend in the queue before
215   // being silently dropped.
216   virtual void SetDatagramMaxTimeInQueue(absl::Duration max_time_in_queue) = 0;
217 };
218 
219 }  // namespace webtransport
220 
221 #endif  // QUICHE_WEB_TRANSPORT_WEB_TRANSPORT_H_
222