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