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 #include <quic/state/StateData.h>
10
11 #include <quic/state/QuicStreamUtilities.h>
12
13 namespace quic {
QuicStreamState(StreamId idIn,QuicConnectionStateBase & connIn)14 QuicStreamState::QuicStreamState(StreamId idIn, QuicConnectionStateBase& connIn)
15 : conn(connIn), id(idIn) {
16 // Note: this will set a windowSize for a locally-initiated unidirectional
17 // stream even though that value is meaningless.
18 flowControlState.windowSize = isUnidirectionalStream(idIn)
19 ? conn.transportSettings.advertisedInitialUniStreamWindowSize
20 : isLocalStream(connIn.nodeType, idIn)
21 ? conn.transportSettings.advertisedInitialBidiLocalStreamWindowSize
22 : conn.transportSettings.advertisedInitialBidiRemoteStreamWindowSize;
23 flowControlState.advertisedMaxOffset = isUnidirectionalStream(idIn)
24 ? conn.transportSettings.advertisedInitialUniStreamWindowSize
25 : isLocalStream(connIn.nodeType, idIn)
26 ? conn.transportSettings.advertisedInitialBidiLocalStreamWindowSize
27 : conn.transportSettings.advertisedInitialBidiRemoteStreamWindowSize;
28 // Note: this will set a peerAdvertisedMaxOffset for a peer-initiated
29 // unidirectional stream even though that value is meaningless.
30 flowControlState.peerAdvertisedMaxOffset = isUnidirectionalStream(idIn)
31 ? conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetUni
32 : isLocalStream(connIn.nodeType, idIn)
33 ? conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote
34 : conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiLocal;
35 if (isUnidirectionalStream(idIn)) {
36 if (isLocalStream(connIn.nodeType, idIn)) {
37 recvState = StreamRecvState::Invalid;
38 } else {
39 sendState = StreamSendState::Invalid;
40 }
41 }
42 }
43
operator <<(std::ostream & os,const QuicConnectionStateBase & st)44 std::ostream& operator<<(std::ostream& os, const QuicConnectionStateBase& st) {
45 if (st.clientConnectionId) {
46 os << "client CID=" << *st.clientConnectionId;
47 } else {
48 os << "client CID=None";
49 }
50 if (st.serverConnectionId) {
51 os << " server CID=" << *st.serverConnectionId;
52 } else {
53 os << " server CID=None";
54 }
55 os << " peer address=" << st.peerAddress;
56 return os;
57 }
58
AckStateVersion(uint64_t initialVersion,uint64_t handshakeVersion,uint64_t appDataVersion)59 AckStateVersion::AckStateVersion(
60 uint64_t initialVersion,
61 uint64_t handshakeVersion,
62 uint64_t appDataVersion)
63 : initialAckStateVersion(initialVersion),
64 handshakeAckStateVersion(handshakeVersion),
65 appDataAckStateVersion(appDataVersion) {}
66
operator ==(const AckStateVersion & other) const67 bool AckStateVersion::operator==(const AckStateVersion& other) const {
68 return initialAckStateVersion == other.initialAckStateVersion &&
69 handshakeAckStateVersion == other.handshakeAckStateVersion &&
70 appDataAckStateVersion == other.appDataAckStateVersion;
71 }
72
operator !=(const AckStateVersion & other) const73 bool AckStateVersion::operator!=(const AckStateVersion& other) const {
74 return !operator==(other);
75 }
76
PacingRate(std::chrono::microseconds intervalIn,uint64_t burstSizeIn)77 PacingRate::PacingRate(
78 std::chrono::microseconds intervalIn,
79 uint64_t burstSizeIn)
80 : interval(intervalIn), burstSize(burstSizeIn) {}
81
setInterval(std::chrono::microseconds intervalIn)82 PacingRate::Builder&& PacingRate::Builder::setInterval(
83 std::chrono::microseconds intervalIn) && {
84 interval_ = intervalIn;
85 return std::move(*this);
86 }
87
setBurstSize(uint64_t burstSizeIn)88 PacingRate::Builder&& PacingRate::Builder::setBurstSize(
89 uint64_t burstSizeIn) && {
90 burstSize_ = burstSizeIn;
91 return std::move(*this);
92 }
93
build()94 PacingRate PacingRate::Builder::build() && {
95 return PacingRate(interval_, burstSize_);
96 }
97
AckPacket(TimePoint sentTimeIn,uint32_t encodedSizeIn,folly::Optional<OutstandingPacket::LastAckedPacketInfo> lastAckedPacketInfoIn,uint64_t totalBytesSentThenIn,bool isAppLimitedIn)98 CongestionController::AckEvent::AckPacket::AckPacket(
99 TimePoint sentTimeIn,
100 uint32_t encodedSizeIn,
101 folly::Optional<OutstandingPacket::LastAckedPacketInfo>
102 lastAckedPacketInfoIn,
103 uint64_t totalBytesSentThenIn,
104 bool isAppLimitedIn)
105 : sentTime(sentTimeIn),
106 encodedSize(encodedSizeIn),
107 lastAckedPacketInfo(std::move(lastAckedPacketInfoIn)),
108 totalBytesSentThen(totalBytesSentThenIn),
109 isAppLimited(isAppLimitedIn) {}
110
111 CongestionController::AckEvent::AckPacket::Builder&&
setSentTime(TimePoint sentTimeIn)112 CongestionController::AckEvent::AckPacket::Builder::setSentTime(
113 TimePoint sentTimeIn) {
114 sentTime = sentTimeIn;
115 return std::move(*this);
116 }
117
118 CongestionController::AckEvent::AckPacket::Builder&&
setEncodedSize(uint32_t encodedSizeIn)119 CongestionController::AckEvent::AckPacket::Builder::setEncodedSize(
120 uint32_t encodedSizeIn) {
121 encodedSize = encodedSizeIn;
122 return std::move(*this);
123 }
124
125 CongestionController::AckEvent::AckPacket::Builder&&
setLastAckedPacketInfo(folly::Optional<OutstandingPacket::LastAckedPacketInfo> lastAckedPacketInfoIn)126 CongestionController::AckEvent::AckPacket::Builder::setLastAckedPacketInfo(
127 folly::Optional<OutstandingPacket::LastAckedPacketInfo>
128 lastAckedPacketInfoIn) {
129 lastAckedPacketInfo = lastAckedPacketInfoIn;
130 return std::move(*this);
131 }
132
133 CongestionController::AckEvent::AckPacket::Builder&&
setTotalBytesSentThen(uint64_t totalBytesSentThenIn)134 CongestionController::AckEvent::AckPacket::Builder::setTotalBytesSentThen(
135 uint64_t totalBytesSentThenIn) {
136 totalBytesSentThen = totalBytesSentThenIn;
137 return std::move(*this);
138 }
139
140 CongestionController::AckEvent::AckPacket::Builder&&
setAppLimited(bool appLimitedIn)141 CongestionController::AckEvent::AckPacket::Builder::setAppLimited(
142 bool appLimitedIn) {
143 isAppLimited = appLimitedIn;
144 return std::move(*this);
145 }
146
147 CongestionController::AckEvent::AckPacket
build()148 CongestionController::AckEvent::AckPacket::Builder::build() && {
149 return CongestionController::AckEvent::AckPacket(
150 sentTime,
151 encodedSize,
152 std::move(lastAckedPacketInfo),
153 totalBytesSentThen,
154 isAppLimited);
155 }
156
retireAndSwitchPeerConnectionIds()157 bool QuicConnectionStateBase::retireAndSwitchPeerConnectionIds() {
158 const auto end = peerConnectionIds.end();
159 auto replacementConnIdDataIt{end};
160 auto currentConnIdDataIt{end};
161
162 auto& mainPeerId = nodeType == QuicNodeType::Client ? serverConnectionId
163 : clientConnectionId;
164 if (!mainPeerId) {
165 throw QuicTransportException(
166 "Attempting to retire null peer conn id",
167 TransportErrorCode::INTERNAL_ERROR);
168 }
169
170 // Retrieve the sequence number of the current cId, and find an unused
171 // ConnectionIdData.
172 for (auto it = peerConnectionIds.begin(); it != end; it++) {
173 if (replacementConnIdDataIt != end && currentConnIdDataIt != end) {
174 break;
175 }
176
177 if (it->connId == mainPeerId) {
178 currentConnIdDataIt = it;
179 } else if (replacementConnIdDataIt == end) {
180 replacementConnIdDataIt = it;
181 }
182 }
183 if (replacementConnIdDataIt == end) {
184 return false;
185 }
186 DCHECK(currentConnIdDataIt != end);
187 pendingEvents.frames.push_back(
188 RetireConnectionIdFrame(currentConnIdDataIt->sequenceNumber));
189 mainPeerId = replacementConnIdDataIt->connId;
190
191 peerConnectionIds.erase(currentConnIdDataIt);
192 return true;
193 }
194
195 } // namespace quic
196