1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8 
9 #pragma once
10 
11 #include <folly/Expected.h>
12 #include <folly/io/async/AsyncUDPSocket.h>
13 
14 #include <quic/QuicException.h>
15 #include <quic/api/IoBufQuicBatch.h>
16 #include <quic/api/QuicPacketScheduler.h>
17 #include <quic/api/QuicSocket.h>
18 #include <quic/state/StateData.h>
19 
20 // Function to schedule writing data to socket. Return number of packets
21 // successfully scheduled
22 namespace quic {
23 
24 struct DataPathResult {
25   bool buildSuccess{false};
26   bool writeSuccess{false};
27   folly::Optional<SchedulingResult> result;
28   uint64_t encodedSize{0};
29   uint64_t encodedBodySize{0};
30 
makeBuildFailureDataPathResult31   static DataPathResult makeBuildFailure() {
32     return DataPathResult();
33   }
34 
makeWriteResultDataPathResult35   static DataPathResult makeWriteResult(
36       bool writeSuc,
37       SchedulingResult&& res,
38       uint64_t encodedSizeIn,
39       uint64_t encodedBodySizeIn) {
40     return DataPathResult(
41         writeSuc, std::move(res), encodedSizeIn, encodedBodySizeIn);
42   }
43 
44  private:
45   explicit DataPathResult() = default;
46 
DataPathResultDataPathResult47   explicit DataPathResult(
48       bool writeSuc,
49       SchedulingResult&& res,
50       uint64_t encodedSizeIn,
51       uint64_t encodedBodySizeIn)
52       : buildSuccess(true),
53         writeSuccess(writeSuc),
54         result(std::move(res)),
55         encodedSize(encodedSizeIn),
56         encodedBodySize(encodedBodySizeIn) {}
57 };
58 
59 using DataPathFunc = std::function<DataPathResult(
60     QuicConnectionStateBase&,
61     PacketHeader,
62     PacketNumberSpace,
63     PacketNum,
64     uint64_t,
65     QuicPacketScheduler&,
66     uint64_t,
67     IOBufQuicBatch&,
68     const Aead&,
69     const PacketNumberCipher&)>;
70 
71 using HeaderBuilder = std::function<PacketHeader(
72     const ConnectionId& srcConnId,
73     const ConnectionId& dstConnId,
74     PacketNum packetNum,
75     QuicVersion version,
76     const std::string& token)>;
77 
78 using WritableBytesFunc =
79     std::function<uint64_t(const QuicConnectionStateBase& conn)>;
80 
81 // Encapsulating the return value for the write functions.
82 // Useful because probes can go over the packet limit.
83 struct WriteQuicDataResult {
84   uint64_t packetsWritten{};
85   uint64_t probesWritten{};
86 };
87 
88 /**
89  * Attempts to write data from all frames in the QUIC connection into the UDP
90  * socket supplied with the aead and the headerCipher.
91  */
92 WriteQuicDataResult writeQuicDataToSocket(
93     folly::AsyncUDPSocket& sock,
94     QuicConnectionStateBase& connection,
95     const ConnectionId& srcConnId,
96     const ConnectionId& dstConnId,
97     const Aead& aead,
98     const PacketNumberCipher& headerCipher,
99     QuicVersion version,
100     uint64_t packetLimit);
101 
102 /**
103  * Writes only the crypto and ack frames to the socket.
104  *
105  * return the number of packets written to socket.
106  */
107 WriteQuicDataResult writeCryptoAndAckDataToSocket(
108     folly::AsyncUDPSocket& sock,
109     QuicConnectionStateBase& connection,
110     const ConnectionId& srcConnId,
111     const ConnectionId& dstConnId,
112     LongHeader::Types packetType,
113     Aead& cleartextCipher,
114     const PacketNumberCipher& headerCipher,
115     QuicVersion version,
116     uint64_t packetLimit,
117     const std::string& token = std::string());
118 
119 /**
120  * Writes out all the data streams without writing out crypto streams.
121  * This is useful when the crypto stream still needs to be sent in separate
122  * packets and cannot use the encryption of the data key.
123  */
124 WriteQuicDataResult writeQuicDataExceptCryptoStreamToSocket(
125     folly::AsyncUDPSocket& socket,
126     QuicConnectionStateBase& connection,
127     const ConnectionId& srcConnId,
128     const ConnectionId& dstConnId,
129     const Aead& aead,
130     const PacketNumberCipher& headerCipher,
131     QuicVersion version,
132     uint64_t packetLimit);
133 
134 /**
135  * Writes frame data including zero rtt data to the socket with the supplied
136  * zero rtt cipher.
137  */
138 uint64_t writeZeroRttDataToSocket(
139     folly::AsyncUDPSocket& socket,
140     QuicConnectionStateBase& connection,
141     const ConnectionId& srcConnId,
142     const ConnectionId& dstConnId,
143     const Aead& aead,
144     const PacketNumberCipher& headerCipher,
145     QuicVersion version,
146     uint64_t packetLimit);
147 
148 /**
149  * Whether we should and can write data.
150  *
151  */
152 WriteDataReason shouldWriteData(const QuicConnectionStateBase& conn);
153 bool hasAckDataToWrite(const QuicConnectionStateBase& conn);
154 WriteDataReason hasNonAckDataToWrite(const QuicConnectionStateBase& conn);
155 
156 /**
157  * Invoked when the written stream data was new stream data.
158  */
159 void handleNewStreamDataWritten(
160     QuicStreamLike& stream,
161     uint64_t frameLen,
162     bool frameFin);
163 
164 /**
165  * Invoked when the stream data written was retransmitted data.
166  */
167 void handleRetransmissionWritten(
168     QuicStreamLike& stream,
169     uint64_t frameOffset,
170     uint64_t frameLen,
171     bool frameFin,
172     std::deque<StreamBuffer>::iterator lossBufferIter);
173 
174 /**
175  * Update the connection and stream state after stream data is written and deal
176  * with new data, as well as retranmissions. Returns true if the data sent is
177  * new data.
178  */
179 bool handleStreamWritten(
180     QuicConnectionStateBase& conn,
181     QuicStreamLike& stream,
182     uint64_t frameOffset,
183     uint64_t frameLen,
184     bool frameFin,
185     PacketNum packetNum,
186     PacketNumberSpace packetNumberSpace);
187 
188 bool handleStreamBufMetaWritten(
189     QuicConnectionStateBase& conn,
190     QuicStreamState& stream,
191     uint64_t frameOffset,
192     uint64_t frameLen,
193     bool frameFin,
194     PacketNum packetNum,
195     PacketNumberSpace packetNumberSpace);
196 
197 /**
198  * Update the connection state after sending a new packet.
199  */
200 void updateConnection(
201     QuicConnectionStateBase& conn,
202     folly::Optional<PacketEvent> packetEvent,
203     RegularQuicWritePacket packet,
204     TimePoint time,
205     uint32_t encodedSize,
206     uint32_t encodedBodySize,
207     bool isDSRPacket);
208 
209 /**
210  * Returns the minimum available bytes window out of path validation rate
211  * limiting, 0-rtt total bytes sent limiting, and the congestion controller.
212  */
213 uint64_t congestionControlWritableBytes(const QuicConnectionStateBase& conn);
214 
215 uint64_t unlimitedWritableBytes(const QuicConnectionStateBase&);
216 
217 void writeCloseCommon(
218     folly::AsyncUDPSocket& sock,
219     QuicConnectionStateBase& connection,
220     PacketHeader&& header,
221     folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
222     const Aead& aead,
223     const PacketNumberCipher& headerCipher);
224 
225 /**
226  * Writes a LongHeader packet with a close frame.
227  * The close frame type written depends on the type of error in closeDetails.
228  */
229 void writeLongClose(
230     folly::AsyncUDPSocket& sock,
231     QuicConnectionStateBase& connection,
232     const ConnectionId& srcConnId,
233     const ConnectionId& dstConnId,
234     LongHeader::Types headerType,
235     folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
236     const Aead& aead,
237     const PacketNumberCipher& headerCipher,
238     QuicVersion);
239 
240 /**
241  * Write a short header packet with a close frame.
242  * The close frame type written depends on the type of error in closeDetails.
243  */
244 void writeShortClose(
245     folly::AsyncUDPSocket& sock,
246     QuicConnectionStateBase& connection,
247     const ConnectionId& connId,
248     folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
249     const Aead& aead,
250     const PacketNumberCipher& headerCipher);
251 
252 /**
253  * Encrypts the packet header for the header type.
254  * This will overwrite the header with the encrypted header form. It will verify
255  * whether or not there are enough bytes to sample for the header encryption
256  * from the encryptedBody via a CHECK.
257  */
258 void encryptPacketHeader(
259     HeaderForm headerForm,
260     uint8_t* header,
261     size_t headerLen,
262     const uint8_t* encryptedBody,
263     size_t bodyLen,
264     const PacketNumberCipher& headerCipher);
265 
266 /**
267  * Writes the connections data to the socket using the header
268  * builder as well as the scheduler. This will write the amount of
269  * data allowed by the writableBytesFunc and will only write a maximum
270  * number of packetLimit packets at each invocation.
271  */
272 uint64_t writeConnectionDataToSocket(
273     folly::AsyncUDPSocket& sock,
274     QuicConnectionStateBase& connection,
275     const ConnectionId& srcConnId,
276     const ConnectionId& dstConnId,
277     HeaderBuilder builder,
278     PacketNumberSpace pnSpace,
279     QuicPacketScheduler& scheduler,
280     const WritableBytesFunc& writableBytesFunc,
281     uint64_t packetLimit,
282     const Aead& aead,
283     const PacketNumberCipher& headerCipher,
284     QuicVersion version,
285     const std::string& token = std::string());
286 
287 uint64_t writeProbingDataToSocket(
288     folly::AsyncUDPSocket& sock,
289     QuicConnectionStateBase& connection,
290     const ConnectionId& srcConnId,
291     const ConnectionId& dstConnId,
292     const HeaderBuilder& builder,
293     EncryptionLevel encryptionLevel,
294     PacketNumberSpace pnSpace,
295     FrameScheduler scheduler,
296     uint8_t probesToSend,
297     const Aead& aead,
298     const PacketNumberCipher& headerCipher,
299     QuicVersion version,
300     const std::string& token = std::string());
301 
302 uint64_t writeD6DProbeToSocket(
303     folly::AsyncUDPSocket& sock,
304     QuicConnectionStateBase& connection,
305     const ConnectionId& srcConnId,
306     const ConnectionId& dstConnId,
307     const Aead& aead,
308     const PacketNumberCipher& headerCipher,
309     QuicVersion version);
310 
311 HeaderBuilder LongHeaderBuilder(LongHeader::Types packetType);
312 HeaderBuilder ShortHeaderBuilder();
313 
314 void maybeSendStreamLimitUpdates(QuicConnectionStateBase& conn);
315 
316 void implicitAckCryptoStream(
317     QuicConnectionStateBase& conn,
318     EncryptionLevel encryptionLevel);
319 void handshakeConfirmed(QuicConnectionStateBase& conn);
320 bool hasInitialOrHandshakeCiphers(QuicConnectionStateBase& conn);
321 
322 bool writeLoopTimeLimit(
323     TimePoint loopBeginTime,
324     const QuicConnectionStateBase& connection);
325 
326 } // namespace quic
327