SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CCRakNetSlidingWindow.cpp
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
16 #include "slikenet/CCRakNetSlidingWindow.h"
17
18 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
19
20 static const double UNSET_TIME_US=-1;
21
22 #if CC_TIME_TYPE_BYTES==4
23 static const CCTimeType SYN=10;
24 #else
25 static const CCTimeType SYN=10000;
26 #endif
27
28 #include "slikenet/MTUSize.h"
29 #include <stdio.h>
30 #include <cmath>
31 #include <stdlib.h>
32 #include "slikenet/assert.h"
33 #include "slikenet/alloca.h"
34
35 using namespace SLNet;
36
37 // ****************************************************** PUBLIC METHODS ******************************************************
38
39 CCRakNetSlidingWindow::CCRakNetSlidingWindow()
40 {
41 }
42 // ----------------------------------------------------------------------------------------------------------------------------
43 CCRakNetSlidingWindow::~CCRakNetSlidingWindow()
44 {
45
46 }
47 // ----------------------------------------------------------------------------------------------------------------------------
48 void CCRakNetSlidingWindow::Init(CCTimeType curTime, uint32_t maxDatagramPayload)
49 {
50 (void) curTime;
51
52 lastRtt=estimatedRTT=deviationRtt=UNSET_TIME_US;
53 RakAssert(maxDatagramPayload <= MAXIMUM_MTU_SIZE);
54 MAXIMUM_MTU_INCLUDING_UDP_HEADER=maxDatagramPayload;
55 cwnd=maxDatagramPayload;
56 ssThresh=0.0;
57 oldestUnsentAck=0;
58 nextDatagramSequenceNumber=0;
59 nextCongestionControlBlock=0;
60 backoffThisBlock=speedUpThisBlock=false;
61 expectedNextSequenceNumber=0;
62 _isContinuousSend=false;
63 }
64 // ----------------------------------------------------------------------------------------------------------------------------
65 void CCRakNetSlidingWindow::Update(CCTimeType curTime, bool hasDataToSendOrResend)
66 {
67 (void) curTime;
68 (void) hasDataToSendOrResend;
69 }
70 // ----------------------------------------------------------------------------------------------------------------------------
71 int CCRakNetSlidingWindow::GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
72 {
73 (void) curTime;
74 (void) isContinuousSend;
75 (void) timeSinceLastTick;
76
77 return unacknowledgedBytes;
78 }
79 // ----------------------------------------------------------------------------------------------------------------------------
80 int CCRakNetSlidingWindow::GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
81 {
82 (void) curTime;
83 (void) timeSinceLastTick;
84
85 _isContinuousSend=isContinuousSend;
86
87 if (unacknowledgedBytes<=cwnd)
88 return (int) (cwnd-unacknowledgedBytes);
89 else
90 return 0;
91 }
92 // ----------------------------------------------------------------------------------------------------------------------------
93 bool CCRakNetSlidingWindow::ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick)
94 {
95 CCTimeType rto = GetSenderRTOForACK();
96 (void) estimatedTimeToNextTick;
97
98 // iphone crashes on comparison between double and int64 http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
99 if (rto==(CCTimeType) UNSET_TIME_US)
100 {
101 // Unknown how long until the remote system will retransmit, so better send right away
102 return true;
103 }
104
105 return curTime >= oldestUnsentAck + SYN;
106 }
107 // ----------------------------------------------------------------------------------------------------------------------------
108 DatagramSequenceNumberType CCRakNetSlidingWindow::GetNextDatagramSequenceNumber(void)
109 {
110 return nextDatagramSequenceNumber;
111 }
112 // ----------------------------------------------------------------------------------------------------------------------------
113 DatagramSequenceNumberType CCRakNetSlidingWindow::GetAndIncrementNextDatagramSequenceNumber(void)
114 {
115 DatagramSequenceNumberType dsnt=nextDatagramSequenceNumber;
116 nextDatagramSequenceNumber++;
117 return dsnt;
118 }
119 // ----------------------------------------------------------------------------------------------------------------------------
120 void CCRakNetSlidingWindow::OnSendBytes(CCTimeType curTime, uint32_t numBytes)
121 {
122 (void) curTime;
123 (void) numBytes;
124 }
125 // ----------------------------------------------------------------------------------------------------------------------------
126 void CCRakNetSlidingWindow::OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime)
127 {
128 (void) curTime;
129 (void) sizeInBytes;
130 (void) datagramSequenceNumber;
131 }
132 // ----------------------------------------------------------------------------------------------------------------------------
133 bool CCRakNetSlidingWindow::OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount)
134 {
135 (void) curTime;
136 (void) sizeInBytes;
137 (void) isContinuousSend;
138
139 if (oldestUnsentAck==0)
140 oldestUnsentAck=curTime;
141
142 if (datagramSequenceNumber==expectedNextSequenceNumber)
143 {
144 *skippedMessageCount=0;
145 expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
146 }
147 else if (GreaterThan(datagramSequenceNumber, expectedNextSequenceNumber))
148 {
149 *skippedMessageCount=datagramSequenceNumber-expectedNextSequenceNumber;
150 // Sanity check, just use timeout resend if this was really valid
151 if (*skippedMessageCount>1000)
152 {
153 // During testing, the nat punchthrough server got 51200 on the first packet. I have no idea where this comes from, but has happened twice
154 if (*skippedMessageCount>(uint32_t)50000)
155 return false;
156 *skippedMessageCount=1000;
157 }
158 expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
159 }
160 else
161 {
162 *skippedMessageCount=0;
163 }
164
165 return true;
166 }
167 // ----------------------------------------------------------------------------------------------------------------------------
168 void CCRakNetSlidingWindow::OnResend(CCTimeType curTime, SLNet::TimeUS nextActionTime)
169 {
170 (void) curTime;
171 (void) nextActionTime;
172
173 if (_isContinuousSend && backoffThisBlock==false && cwnd>MAXIMUM_MTU_INCLUDING_UDP_HEADER*2)
174 {
175 // Spec says 1/2 cwnd, but it never recovers because cwnd increases too slowly
176 //ssThresh=cwnd-8.0 * (MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd);
177 ssThresh=cwnd/2;
178 if (ssThresh<MAXIMUM_MTU_INCLUDING_UDP_HEADER)
179 ssThresh=MAXIMUM_MTU_INCLUDING_UDP_HEADER;
180 cwnd=MAXIMUM_MTU_INCLUDING_UDP_HEADER;
181
182 // Only backoff once per period
183 nextCongestionControlBlock=nextDatagramSequenceNumber;
184 backoffThisBlock=true;
185
186 // CC PRINTF
187 //printf("-- %.0f (Resend) Enter slow start.\n", cwnd);
188 }
189 }
190 // ----------------------------------------------------------------------------------------------------------------------------
191 void CCRakNetSlidingWindow::OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber)
192 {
193 (void) nakSequenceNumber;
194 (void) curTime;
195
196 if (_isContinuousSend && backoffThisBlock==false)
197 {
198 // Start congestion avoidance
199 ssThresh=cwnd/2;
200
201 // CC PRINTF
202 //printf("- %.0f (NAK) Set congestion avoidance.\n", cwnd);
203 }
204 }
205 // ----------------------------------------------------------------------------------------------------------------------------
206 void CCRakNetSlidingWindow::OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber )
207 {
208 (void) _B;
209 (void) totalUserDataBytesAcked;
210 (void) _AS;
211 (void) hasBAndAS;
212 (void) curTime;
213 (void) rtt;
214
215 lastRtt=(double) rtt;
216 if (estimatedRTT==UNSET_TIME_US)
217 {
218 estimatedRTT=(double) rtt;
219 deviationRtt=(double)rtt;
220 }
221 else
222 {
223 double d = .05;
224 double difference = rtt - estimatedRTT;
225 estimatedRTT = estimatedRTT + d * difference;
226 deviationRtt = deviationRtt + d * (std::abs(difference) - deviationRtt);
227 }
228
229 _isContinuousSend=isContinuousSend;
230
231 if (isContinuousSend==false)
232 return;
233
234 bool isNewCongestionControlPeriod;
235 isNewCongestionControlPeriod = GreaterThan(sequenceNumber, nextCongestionControlBlock);
236
237 if (isNewCongestionControlPeriod)
238 {
239 backoffThisBlock=false;
240 speedUpThisBlock=false;
241 nextCongestionControlBlock=nextDatagramSequenceNumber;
242 }
243
244 if (IsInSlowStart())
245 {
246 cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER;
247 if (cwnd > ssThresh && ssThresh!=0)
248 cwnd = ssThresh + MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd;
249
250 // CC PRINTF
251 // printf("++ %.0f Slow start increase.\n", cwnd);
252
253 }
254 else if (isNewCongestionControlPeriod)
255 {
256 cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd;
257
258 // CC PRINTF
259 // printf("+ %.0f Congestion avoidance increase.\n", cwnd);
260 }
261 }
262 // ----------------------------------------------------------------------------------------------------------------------------
263 void CCRakNetSlidingWindow::OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber )
264 {
265 (void) curTime;
266 (void) sequenceNumber;
267 }
268 // ----------------------------------------------------------------------------------------------------------------------------
269 void CCRakNetSlidingWindow::OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS)
270 {
271 (void) curTime;
272 (void) _B;
273 (void) _AS;
274
275 *hasBAndAS=false;
276 }
277 // ----------------------------------------------------------------------------------------------------------------------------
278 void CCRakNetSlidingWindow::OnSendAck(CCTimeType curTime, uint32_t numBytes)
279 {
280 (void) curTime;
281 (void) numBytes;
282
283 oldestUnsentAck=0;
284 }
285 // ----------------------------------------------------------------------------------------------------------------------------
286 void CCRakNetSlidingWindow::OnSendNACK(CCTimeType curTime, uint32_t numBytes)
287 {
288 (void) curTime;
289 (void) numBytes;
290
291 }
292 // ----------------------------------------------------------------------------------------------------------------------------
293 CCTimeType CCRakNetSlidingWindow::GetRTOForRetransmission(unsigned char timesSent) const
294 {
295 (void) timesSent;
296
297 #if CC_TIME_TYPE_BYTES==4
298 const CCTimeType maxThreshold=2000;
299 //const CCTimeType minThreshold=100;
300 const CCTimeType additionalVariance=30;
301 #else
302 const CCTimeType maxThreshold=2000000;
303 //const CCTimeType minThreshold=100000;
304 const CCTimeType additionalVariance=30000;
305 #endif
306
307
308 if (estimatedRTT==UNSET_TIME_US)
309 return maxThreshold;
310
311 //double u=1.0f;
312 double u=2.0f;
313 double q=4.0f;
314
315 CCTimeType threshhold = (CCTimeType) (u * estimatedRTT + q * deviationRtt) + additionalVariance;
316 if (threshhold > maxThreshold)
317 return maxThreshold;
318 return threshhold;
319 }
320 // ----------------------------------------------------------------------------------------------------------------------------
321 void CCRakNetSlidingWindow::SetMTU(uint32_t bytes)
322 {
323 RakAssert(bytes < MAXIMUM_MTU_SIZE);
324 MAXIMUM_MTU_INCLUDING_UDP_HEADER=bytes;
325 }
326 // ----------------------------------------------------------------------------------------------------------------------------
327 uint32_t CCRakNetSlidingWindow::GetMTU(void) const
328 {
329 return MAXIMUM_MTU_INCLUDING_UDP_HEADER;
330 }
331 // ----------------------------------------------------------------------------------------------------------------------------
332 BytesPerMicrosecond CCRakNetSlidingWindow::GetLocalReceiveRate(CCTimeType currentTime) const
333 {
334 (void) currentTime;
335
336 return 0; // TODO
337 }
338 // ----------------------------------------------------------------------------------------------------------------------------
339 double CCRakNetSlidingWindow::GetRTT(void) const
340 {
341 if (lastRtt==UNSET_TIME_US)
342 return 0.0;
343 return lastRtt;
344 }
345 // ----------------------------------------------------------------------------------------------------------------------------
346 bool CCRakNetSlidingWindow::GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
347 {
348 // a > b?
349 const DatagramSequenceNumberType halfSpan =(DatagramSequenceNumberType) (((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2);
350 return b!=a && b-a>halfSpan;
351 }
352 // ----------------------------------------------------------------------------------------------------------------------------
353 bool CCRakNetSlidingWindow::LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
354 {
355 // a < b?
356 const DatagramSequenceNumberType halfSpan = ((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2;
357 return b!=a && b-a<halfSpan;
358 }
359 // ----------------------------------------------------------------------------------------------------------------------------
360 uint64_t CCRakNetSlidingWindow::GetBytesPerSecondLimitByCongestionControl(void) const
361 {
362 return 0; // TODO
363 }
364 // ----------------------------------------------------------------------------------------------------------------------------
365 CCTimeType CCRakNetSlidingWindow::GetSenderRTOForACK(void) const
366 {
367 if (lastRtt==UNSET_TIME_US)
368 return (CCTimeType) UNSET_TIME_US;
369 return (CCTimeType)(lastRtt + SYN);
370 }
371 // ----------------------------------------------------------------------------------------------------------------------------
372 bool CCRakNetSlidingWindow::IsInSlowStart(void) const
373 {
374 return cwnd <= ssThresh || ssThresh==0;
375 }
376 // ----------------------------------------------------------------------------------------------------------------------------
377 #endif