1 #include "CCRakNetUDT.h"
2
3 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
4
5 #include "Rand.h"
6 #include "MTUSize.h"
7 #include <stdio.h>
8 #include <math.h>
9 #include <stdlib.h>
10 //#include <memory.h>
11 #include "RakAssert.h"
12 #include "RakAlloca.h"
13
14 using namespace RakNet;
15
16 static const double UNSET_TIME_US=-1;
17 static const double CWND_MIN_THRESHOLD=2.0;
18 static const double UNDEFINED_TRANSFER_RATE=0.0;
19 /// Interval at which to update aspects of the system
20 /// 1. send acks
21 /// 2. update time interval between outgoing packets
22 /// 3, Yodate retransmit timeout
23 #if CC_TIME_TYPE_BYTES==4
24 static const CCTimeType SYN=10;
25 #else
26 static const CCTimeType SYN=10000;
27 #endif
28
29 #if CC_TIME_TYPE_BYTES==4
30 #define MAX_RTT 1000
31 #define RTT_TOLERANCE 30
32 #else
33 #define MAX_RTT 1000000
34 #define RTT_TOLERANCE 30000
35 #endif
36
37
38 double RTTVarMultiple=4.0;
39
40
41 // ****************************************************** PUBLIC METHODS ******************************************************
42
CCRakNetUDT()43 CCRakNetUDT::CCRakNetUDT()
44 {
45 }
46
47 // ----------------------------------------------------------------------------------------------------------------------------
48
~CCRakNetUDT()49 CCRakNetUDT::~CCRakNetUDT()
50 {
51 }
52 // ----------------------------------------------------------------------------------------------------------------------------
Init(CCTimeType curTime,uint32_t maxDatagramPayload)53 void CCRakNetUDT::Init(CCTimeType curTime, uint32_t maxDatagramPayload)
54 {
55 (void) curTime;
56
57 nextSYNUpdate=0;
58 packetPairRecieptHistoryWriteIndex=0;
59 packetArrivalHistoryWriteIndex=0;
60 packetArrivalHistoryWriteCount=0;
61 RTT=UNSET_TIME_US;
62 // RTTVar=UNSET_TIME_US;
63 isInSlowStart=true;
64 NAKCount=1000;
65 AvgNAKNum=1;
66 DecInterval=1;
67 DecCount=0;
68 nextDatagramSequenceNumber=0;
69 lastPacketPairPacketArrivalTime=0;
70 lastPacketPairSequenceNumber=(DatagramSequenceNumberType)(const uint32_t)-1;
71 lastPacketArrivalTime=0;
72 CWND=CWND_MIN_THRESHOLD;
73 lastUpdateWindowSizeAndAck=0;
74 lastTransmitOfBAndAS=0;
75 ExpCount=1.0;
76 totalUserDataBytesSent=0;
77 oldestUnsentAck=0;
78 MAXIMUM_MTU_INCLUDING_UDP_HEADER=maxDatagramPayload;
79 CWND_MAX_THRESHOLD=RESEND_BUFFER_ARRAY_LENGTH;
80 #if CC_TIME_TYPE_BYTES==4
81 const BytesPerMicrosecond DEFAULT_TRANSFER_RATE=(BytesPerMicrosecond) 3.6;
82 #else
83 const BytesPerMicrosecond DEFAULT_TRANSFER_RATE=(BytesPerMicrosecond) .0036;
84 #endif
85
86 #if CC_TIME_TYPE_BYTES==4
87 lastRttOnIncreaseSendRate=1000;
88 #else
89 lastRttOnIncreaseSendRate=1000000;
90 #endif
91 nextCongestionControlBlock=0;
92 lastRtt=0;
93
94 // B=DEFAULT_TRANSFER_RATE;
95 AS=UNDEFINED_TRANSFER_RATE;
96 const MicrosecondsPerByte DEFAULT_BYTE_INTERVAL=(MicrosecondsPerByte) (1.0/DEFAULT_TRANSFER_RATE);
97 SND=DEFAULT_BYTE_INTERVAL;
98 expectedNextSequenceNumber=0;
99 sendBAndASCount=0;
100 packetArrivalHistoryContinuousGapsIndex=0;
101 //packetPairRecipetHistoryGapsIndex=0;
102 hasWrittenToPacketPairReceiptHistory=false;
103 InitPacketArrivalHistory();
104
105 estimatedLinkCapacityBytesPerSecond=0;
106 bytesCanSendThisTick=0;
107 hadPacketlossThisBlock=false;
108 pingsLastInterval.Clear(__FILE__,__LINE__);
109 }
110 // ----------------------------------------------------------------------------------------------------------------------------
SetMTU(uint32_t bytes)111 void CCRakNetUDT::SetMTU(uint32_t bytes)
112 {
113 MAXIMUM_MTU_INCLUDING_UDP_HEADER=bytes;
114 }
115 // ----------------------------------------------------------------------------------------------------------------------------
GetMTU(void) const116 uint32_t CCRakNetUDT::GetMTU(void) const
117 {
118 return MAXIMUM_MTU_INCLUDING_UDP_HEADER;
119 }
120 // ----------------------------------------------------------------------------------------------------------------------------
Update(CCTimeType curTime,bool hasDataToSendOrResend)121 void CCRakNetUDT::Update(CCTimeType curTime, bool hasDataToSendOrResend)
122 {
123 (void) hasDataToSendOrResend;
124 (void) curTime;
125
126 return;
127
128 // I suspect this is causing major lag
129
130 /*
131 if (hasDataToSendOrResend==false)
132 halveSNDOnNoDataTime=0;
133 else if (halveSNDOnNoDataTime==0)
134 {
135 UpdateHalveSNDOnNoDataTime(curTime);
136 ExpCount=1.0;
137 }
138
139 // If you send, and get no data at all from that time to RTO, then halve send rate7
140 if (HasHalveSNDOnNoDataTimeElapsed(curTime))
141 {
142 /// 2000 bytes per second
143 /// 0.0005 seconds per byte
144 /// 0.5 milliseconds per byte
145 /// 500 microseconds per byte
146 // printf("No incoming data, halving send rate\n");
147 SND*=2.0;
148 CapMinSnd(__FILE__,__LINE__);
149 ExpCount+=1.0;
150 if (ExpCount>8.0)
151 ExpCount=8.0;
152
153 UpdateHalveSNDOnNoDataTime(curTime);
154 }
155 */
156 }
157 // ----------------------------------------------------------------------------------------------------------------------------
GetRetransmissionBandwidth(CCTimeType curTime,CCTimeType timeSinceLastTick,uint32_t unacknowledgedBytes,bool isContinuousSend)158 int CCRakNetUDT::GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
159 {
160 (void) curTime;
161
162 if (isInSlowStart)
163 {
164 uint32_t CWNDLimit = (uint32_t) (CWND*MAXIMUM_MTU_INCLUDING_UDP_HEADER);
165 return CWNDLimit;
166 }
167 return GetTransmissionBandwidth(curTime,timeSinceLastTick,unacknowledgedBytes,isContinuousSend);
168 }
169 // ----------------------------------------------------------------------------------------------------------------------------
GetTransmissionBandwidth(CCTimeType curTime,CCTimeType timeSinceLastTick,uint32_t unacknowledgedBytes,bool isContinuousSend)170 int CCRakNetUDT::GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
171 {
172 (void) curTime;
173
174 if (isInSlowStart)
175 {
176 uint32_t CWNDLimit = (uint32_t) (CWND*MAXIMUM_MTU_INCLUDING_UDP_HEADER-unacknowledgedBytes);
177 return CWNDLimit;
178 }
179 if (bytesCanSendThisTick>0)
180 bytesCanSendThisTick=0;
181
182 #if CC_TIME_TYPE_BYTES==4
183 if (isContinuousSend==false && timeSinceLastTick>100)
184 timeSinceLastTick=100;
185 #else
186 if (isContinuousSend==false && timeSinceLastTick>100000)
187 timeSinceLastTick=100000;
188 #endif
189
190 bytesCanSendThisTick=(int)((double)timeSinceLastTick*((double)1.0/SND)+(double)bytesCanSendThisTick);
191 if (bytesCanSendThisTick>0)
192 return bytesCanSendThisTick;
193 return 0;
194 }
GetBytesPerSecondLimitByCongestionControl(void) const195 uint64_t CCRakNetUDT::GetBytesPerSecondLimitByCongestionControl(void) const
196 {
197 if (isInSlowStart)
198 return 0;
199 #if CC_TIME_TYPE_BYTES==4
200 return (uint64_t) ((double)1.0/(SND*1000.0));
201 #else
202 return (uint64_t) ((double)1.0/(SND*1000000.0));
203 #endif
204 }
205 // ----------------------------------------------------------------------------------------------------------------------------
ShouldSendACKs(CCTimeType curTime,CCTimeType estimatedTimeToNextTick)206 bool CCRakNetUDT::ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick)
207 {
208 CCTimeType rto = GetSenderRTOForACK();
209
210 // iphone crashes on comparison between double and int64 http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
211 if (rto==(CCTimeType) UNSET_TIME_US)
212 {
213 // Unknown how long until the remote system will retransmit, so better send right away
214 return true;
215 }
216
217
218 // CCTimeType remoteRetransmitTime=oldestUnsentAck+rto-RTT*.5;
219 // CCTimeType ackArrivalTimeIfWeDelay=RTT*.5+estimatedTimeToNextTick+curTime;
220 // return ackArrivalTimeIfWeDelay<remoteRetransmitTime;
221
222 // Simplified equation
223 // GU: At least one ACK should be sent per SYN, otherwise your protocol will increase slower.
224 return curTime >= oldestUnsentAck + SYN ||
225 estimatedTimeToNextTick+curTime < oldestUnsentAck+rto-RTT;
226 }
227 // ----------------------------------------------------------------------------------------------------------------------------
GetNextDatagramSequenceNumber(void)228 DatagramSequenceNumberType CCRakNetUDT::GetNextDatagramSequenceNumber(void)
229 {
230 return nextDatagramSequenceNumber;
231 }
232 // ----------------------------------------------------------------------------------------------------------------------------
GetAndIncrementNextDatagramSequenceNumber(void)233 DatagramSequenceNumberType CCRakNetUDT::GetAndIncrementNextDatagramSequenceNumber(void)
234 {
235 DatagramSequenceNumberType dsnt=nextDatagramSequenceNumber;
236 nextDatagramSequenceNumber++;
237 return dsnt;
238 }
239 // ----------------------------------------------------------------------------------------------------------------------------
OnSendBytes(CCTimeType curTime,uint32_t numBytes)240 void CCRakNetUDT::OnSendBytes(CCTimeType curTime, uint32_t numBytes)
241 {
242 (void) curTime;
243
244 totalUserDataBytesSent+=numBytes;
245 if (isInSlowStart==false)
246 bytesCanSendThisTick-=numBytes;
247 }
248
249 // ****************************************************** PROTECTED METHODS ******************************************************
250
SetNextSYNUpdate(CCTimeType currentTime)251 void CCRakNetUDT::SetNextSYNUpdate(CCTimeType currentTime)
252 {
253 nextSYNUpdate+=SYN;
254 if (nextSYNUpdate < currentTime)
255 nextSYNUpdate=currentTime+SYN;
256 }
257 // ----------------------------------------------------------------------------------------------------------------------------
ReceiverCalculateDataArrivalRate(CCTimeType curTime) const258 BytesPerMicrosecond CCRakNetUDT::ReceiverCalculateDataArrivalRate(CCTimeType curTime) const
259 {
260 (void) curTime;
261 // Not an instantaneous measurement
262 /*
263 if (continuousBytesReceivedStartTime!=0 && curTime>continuousBytesReceivedStartTime)
264 {
265 #if CC_TIME_TYPE_BYTES==4
266 const CCTimeType threshold=100;
267 #else
268 const CCTimeType threshold=100000;
269 #endif
270 if (curTime-continuousBytesReceivedStartTime>threshold)
271 return (BytesPerMicrosecond) continuousBytesReceived/(BytesPerMicrosecond) (curTime-continuousBytesReceivedStartTime);
272 }
273
274 return UNDEFINED_TRANSFER_RATE;
275 */
276
277
278 if (packetArrivalHistoryWriteCount<CC_RAKNET_UDT_PACKET_HISTORY_LENGTH)
279 return UNDEFINED_TRANSFER_RATE;
280
281 BytesPerMicrosecond median = ReceiverCalculateDataArrivalRateMedian();
282 int i;
283 const BytesPerMicrosecond oneEighthMedian=median*(1.0/8.0);
284 const BytesPerMicrosecond eightTimesMedian=median*8.0f;
285 BytesPerMicrosecond medianListLength=0.0;
286 BytesPerMicrosecond sum=0.0;
287 // Find average of acceptedMedianValues
288 for (i=0; i < CC_RAKNET_UDT_PACKET_HISTORY_LENGTH; i++)
289 {
290 if (packetArrivalHistory[i]>=oneEighthMedian &&
291 packetArrivalHistory[i]<eightTimesMedian)
292 {
293 medianListLength=medianListLength+1.0;
294 sum+=packetArrivalHistory[i];
295 }
296 }
297 if (medianListLength==0.0)
298 return UNDEFINED_TRANSFER_RATE;
299 return sum/medianListLength;
300 }
301 // ----------------------------------------------------------------------------------------------------------------------------
ReceiverCalculateDataArrivalRateMedian(void) const302 BytesPerMicrosecond CCRakNetUDT::ReceiverCalculateDataArrivalRateMedian(void) const
303 {
304 return CalculateListMedianRecursive(packetArrivalHistory, CC_RAKNET_UDT_PACKET_HISTORY_LENGTH, 0, 0);
305 }
306 // ----------------------------------------------------------------------------------------------------------------------------
CalculateListMedianRecursive(const BytesPerMicrosecond inputList[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH],int inputListLength,int lessThanSum,int greaterThanSum)307 BytesPerMicrosecond CCRakNetUDT::CalculateListMedianRecursive(const BytesPerMicrosecond inputList[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum)
308 {
309 BytesPerMicrosecond lessThanMedian[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH], greaterThanMedian[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH];
310 int lessThanMedianListLength=0, greaterThanMedianListLength=0;
311 BytesPerMicrosecond median=inputList[0];
312 int i;
313 for (i=1; i < inputListLength; i++)
314 {
315 // If same value, spread among lists evenly
316 if (inputList[i]<median || ((i&1)==0 && inputList[i]==median))
317 lessThanMedian[lessThanMedianListLength++]=inputList[i];
318 else
319 greaterThanMedian[greaterThanMedianListLength++]=inputList[i];
320 }
321 RakAssert(CC_RAKNET_UDT_PACKET_HISTORY_LENGTH%2==0);
322 if (lessThanMedianListLength+lessThanSum==greaterThanMedianListLength+greaterThanSum+1 ||
323 lessThanMedianListLength+lessThanSum==greaterThanMedianListLength+greaterThanSum-1)
324 return median;
325
326 if (lessThanMedianListLength+lessThanSum < greaterThanMedianListLength+greaterThanSum)
327 {
328 lessThanMedian[lessThanMedianListLength++]=median;
329 return CalculateListMedianRecursive(greaterThanMedian, greaterThanMedianListLength, lessThanMedianListLength+lessThanSum, greaterThanSum);
330 }
331 else
332 {
333 greaterThanMedian[greaterThanMedianListLength++]=median;
334 return CalculateListMedianRecursive(lessThanMedian, lessThanMedianListLength, lessThanSum, greaterThanMedianListLength+greaterThanSum);
335 }
336 }
337
338 // ----------------------------------------------------------------------------------------------------------------------------
GreaterThan(DatagramSequenceNumberType a,DatagramSequenceNumberType b)339 bool CCRakNetUDT::GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
340 {
341 // a > b?
342 const DatagramSequenceNumberType halfSpan =(DatagramSequenceNumberType) (((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2);
343 return b!=a && b-a>halfSpan;
344 }
345 // ----------------------------------------------------------------------------------------------------------------------------
LessThan(DatagramSequenceNumberType a,DatagramSequenceNumberType b)346 bool CCRakNetUDT::LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
347 {
348 // a < b?
349 const DatagramSequenceNumberType halfSpan = ((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2;
350 return b!=a && b-a<halfSpan;
351 }
352 // ----------------------------------------------------------------------------------------------------------------------------
GetSenderRTOForACK(void) const353 CCTimeType CCRakNetUDT::GetSenderRTOForACK(void) const
354 {
355 if (RTT==UNSET_TIME_US)
356 return (CCTimeType) UNSET_TIME_US;
357 double RTTVar = maxRTT-minRTT;
358 return (CCTimeType)(RTT + RTTVarMultiple * RTTVar + SYN);
359 }
360 // ----------------------------------------------------------------------------------------------------------------------------
GetRTOForRetransmission(void) const361 CCTimeType CCRakNetUDT::GetRTOForRetransmission(void) const
362 {
363 #if CC_TIME_TYPE_BYTES==4
364 const CCTimeType maxThreshold=10000;
365 const CCTimeType minThreshold=100;
366 #else
367 const CCTimeType maxThreshold=1000000;
368 const CCTimeType minThreshold=100000;
369 #endif
370
371 if (RTT==UNSET_TIME_US)
372 {
373 return (CCTimeType) maxThreshold;
374 }
375
376 CCTimeType ret = lastRttOnIncreaseSendRate*2;
377
378 if (ret<minThreshold)
379 return minThreshold;
380 if (ret>maxThreshold)
381 return maxThreshold;
382 return ret;
383 }
384 // ----------------------------------------------------------------------------------------------------------------------------
OnResend(CCTimeType curTime)385 void CCRakNetUDT::OnResend(CCTimeType curTime)
386 {
387 (void) curTime;
388
389 if (isInSlowStart)
390 {
391 if (AS!=UNDEFINED_TRANSFER_RATE)
392 EndSlowStart();
393 return;
394 }
395
396 if (hadPacketlossThisBlock==false)
397 {
398 // Logging
399 // printf("Sending SLOWER due to Resend, Rate=%f MBPS. Rtt=%i\n", GetLocalSendRate(), lastRtt );
400
401 IncreaseTimeBetweenSends();
402 hadPacketlossThisBlock=true;
403 }
404 }
405 // ----------------------------------------------------------------------------------------------------------------------------
OnNAK(CCTimeType curTime,DatagramSequenceNumberType nakSequenceNumber)406 void CCRakNetUDT::OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber)
407 {
408 (void) nakSequenceNumber;
409 (void) curTime;
410
411 if (isInSlowStart)
412 {
413 if (AS!=UNDEFINED_TRANSFER_RATE)
414 EndSlowStart();
415 return;
416 }
417
418 if (hadPacketlossThisBlock==false)
419 {
420 // Logging
421 // printf("Sending SLOWER due to NAK, Rate=%f MBPS. Rtt=%i\n", GetLocalSendRate(), lastRtt );
422 // if (pingsLastInterval.Size()>10)
423 // {
424 // for (int i=0; i < 10; i++)
425 // printf("%i, ", pingsLastInterval[pingsLastInterval.Size()-1-i]/1000);
426 // }
427 // printf("\n");
428 IncreaseTimeBetweenSends();
429
430 hadPacketlossThisBlock=true;
431 }
432 }
433 // ----------------------------------------------------------------------------------------------------------------------------
EndSlowStart(void)434 void CCRakNetUDT::EndSlowStart(void)
435 {
436 RakAssert(isInSlowStart==true);
437 RakAssert(AS!=UNDEFINED_TRANSFER_RATE);
438
439 // This overestimates
440 estimatedLinkCapacityBytesPerSecond=AS * 1000000.0;
441
442 isInSlowStart=false;
443 SND=1.0/AS;
444 CapMinSnd(__FILE__,__LINE__);
445
446 // printf("ENDING SLOW START\n");
447 #if CC_TIME_TYPE_BYTES==4
448 // printf("Initial SND=%f Kilobytes per second\n", 1.0/SND);
449 #else
450 // printf("Initial SND=%f Megabytes per second\n", 1.0/SND);
451 #endif
452 if (SND > .1)
453 PrintLowBandwidthWarning();
454 }
455 // ----------------------------------------------------------------------------------------------------------------------------
OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber,uint32_t sizeInBytes,CCTimeType curTime)456 void CCRakNetUDT::OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime)
457 {
458 (void) datagramSequenceNumber;
459 (void) sizeInBytes;
460 (void) curTime;
461
462 }
463 // ----------------------------------------------------------------------------------------------------------------------------
OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber,bool isContinuousSend,CCTimeType curTime,uint32_t sizeInBytes,uint32_t * skippedMessageCount)464 bool CCRakNetUDT::OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount)
465 {
466 CC_DEBUG_PRINTF_2("R%i ",datagramSequenceNumber.val);
467
468 if (datagramSequenceNumber==expectedNextSequenceNumber)
469 {
470 *skippedMessageCount=0;
471 expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
472 }
473 else if (GreaterThan(datagramSequenceNumber, expectedNextSequenceNumber))
474 {
475 *skippedMessageCount=datagramSequenceNumber-expectedNextSequenceNumber;
476 // Sanity check, just use timeout resend if this was really valid
477 if (*skippedMessageCount>1000)
478 {
479 // During testing, the nat punchthrough server got 51200 on the first packet. I have no idea where this comes from, but has happened twice
480 if (*skippedMessageCount>(uint32_t)50000)
481 return false;
482 *skippedMessageCount=1000;
483 }
484 expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
485 }
486 else
487 {
488 *skippedMessageCount=0;
489 }
490
491 if (curTime>lastPacketArrivalTime)
492 {
493 CCTimeType interval = curTime-lastPacketArrivalTime;
494
495 // printf("Packet arrival gap is %I64u\n", (interval));
496
497 if (isContinuousSend)
498 {
499 continuousBytesReceived+=sizeInBytes;
500 if (continuousBytesReceivedStartTime==0)
501 continuousBytesReceivedStartTime=lastPacketArrivalTime;
502
503
504 mostRecentPacketArrivalHistory=(BytesPerMicrosecond)sizeInBytes/(BytesPerMicrosecond)interval;
505
506 // if (mostRecentPacketArrivalHistory < (BytesPerMicrosecond)0.0035)
507 // {
508 // printf("%s:%i LIKELY BUG: Calculated packetArrivalHistory is below 28.8 Kbps modem\nReport to rakkar@jenkinssoftware.com with file and line number\n", __FILE__, __LINE__);
509 // }
510
511 packetArrivalHistoryContinuousGaps[packetArrivalHistoryContinuousGapsIndex++]=(int) interval;
512 packetArrivalHistoryContinuousGapsIndex&=(CC_RAKNET_UDT_PACKET_HISTORY_LENGTH-1);
513
514 packetArrivalHistoryWriteCount++;
515 packetArrivalHistory[packetArrivalHistoryWriteIndex++]=mostRecentPacketArrivalHistory;
516 // Wrap to 0 at the end of the range
517 // Assumes power of 2 for CC_RAKNET_UDT_PACKET_HISTORY_LENGTH
518 packetArrivalHistoryWriteIndex&=(CC_RAKNET_UDT_PACKET_HISTORY_LENGTH-1);
519 }
520 else
521 {
522 continuousBytesReceivedStartTime=0;
523 continuousBytesReceived=0;
524 }
525
526 lastPacketArrivalTime=curTime;
527 }
528 return true;
529 }
530 // ----------------------------------------------------------------------------------------------------------------------------
OnAck(CCTimeType curTime,CCTimeType rtt,bool hasBAndAS,BytesPerMicrosecond _B,BytesPerMicrosecond _AS,double totalUserDataBytesAcked,bool isContinuousSend,DatagramSequenceNumberType sequenceNumber)531 void CCRakNetUDT::OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber )
532 {
533 #if CC_TIME_TYPE_BYTES==4
534 RakAssert(rtt < 10000);
535 #else
536 RakAssert(rtt < 10000000);
537 #endif
538 (void) _B;
539
540 if (hasBAndAS)
541 {
542 /// RakAssert(_B!=UNDEFINED_TRANSFER_RATE && _AS!=UNDEFINED_TRANSFER_RATE);
543 // B=B * .875 + _B * .125;
544 // AS is packet arrival rate
545 RakAssert(_AS!=UNDEFINED_TRANSFER_RATE);
546 AS=_AS;
547 CC_DEBUG_PRINTF_4("ArrivalRate=%f linkCap=%f incomingLinkCap=%f\n", _AS,B,_B);
548 }
549
550 if (oldestUnsentAck==0)
551 oldestUnsentAck=curTime;
552
553 if (isInSlowStart==true)
554 {
555 nextCongestionControlBlock=nextDatagramSequenceNumber;
556 lastRttOnIncreaseSendRate=rtt;
557 UpdateWindowSizeAndAckOnAckPreSlowStart(totalUserDataBytesAcked);
558 }
559 else
560 {
561 UpdateWindowSizeAndAckOnAckPerSyn(curTime, rtt, isContinuousSend, sequenceNumber);
562 }
563
564 lastUpdateWindowSizeAndAck=curTime;
565 }
566 // ----------------------------------------------------------------------------------------------------------------------------
OnSendAckGetBAndAS(CCTimeType curTime,bool * hasBAndAS,BytesPerMicrosecond * _B,BytesPerMicrosecond * _AS)567 void CCRakNetUDT::OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS)
568 {
569 if (curTime>lastTransmitOfBAndAS+SYN)
570 {
571 *_B=0;
572 *_AS=ReceiverCalculateDataArrivalRate(curTime);
573
574 if (*_AS==UNDEFINED_TRANSFER_RATE)
575 {
576 *hasBAndAS=false;
577 }
578 else
579 {
580 *hasBAndAS=true;
581 }
582 }
583 else
584 {
585 *hasBAndAS=false;
586 }
587 }
588 // ----------------------------------------------------------------------------------------------------------------------------
OnSendAck(CCTimeType curTime,uint32_t numBytes)589 void CCRakNetUDT::OnSendAck(CCTimeType curTime, uint32_t numBytes)
590 {
591 (void) numBytes;
592 (void) curTime;
593
594 // This is not accounted for on the remote system, and thus causes bandwidth to be underutilized
595 //UpdateNextAllowedSend(curTime, numBytes+UDP_HEADER_SIZE);
596
597 oldestUnsentAck=0;
598 }
599 // ----------------------------------------------------------------------------------------------------------------------------
OnSendNACK(CCTimeType curTime,uint32_t numBytes)600 void CCRakNetUDT::OnSendNACK(CCTimeType curTime, uint32_t numBytes)
601 {
602 (void) numBytes;
603 (void) curTime;
604
605 // This is not accounted for on the remote system, and thus causes bandwidth to be underutilized
606 // UpdateNextAllowedSend(curTime, numBytes+UDP_HEADER_SIZE);
607 }
608 // ----------------------------------------------------------------------------------------------------------------------------
UpdateWindowSizeAndAckOnAckPreSlowStart(double totalUserDataBytesAcked)609 void CCRakNetUDT::UpdateWindowSizeAndAckOnAckPreSlowStart(double totalUserDataBytesAcked)
610 {
611 // During slow start, max window size is the number of full packets that have been sent out
612 // CWND=(double) ((double)totalUserDataBytesSent/(double)MAXIMUM_MTU_INCLUDING_UDP_HEADER);
613 CC_DEBUG_PRINTF_3("CWND increasing from %f to %f\n", CWND, (double) ((double)totalUserDataBytesAcked/(double)MAXIMUM_MTU_INCLUDING_UDP_HEADER));
614 CWND=(double) ((double)totalUserDataBytesAcked/(double)MAXIMUM_MTU_INCLUDING_UDP_HEADER);
615 if (CWND>=CWND_MAX_THRESHOLD)
616 {
617 CWND=CWND_MAX_THRESHOLD;
618
619 if (AS!=UNDEFINED_TRANSFER_RATE)
620 EndSlowStart();
621 }
622 if (CWND<CWND_MIN_THRESHOLD)
623 CWND=CWND_MIN_THRESHOLD;
624 }
625 // ----------------------------------------------------------------------------------------------------------------------------
UpdateWindowSizeAndAckOnAckPerSyn(CCTimeType curTime,CCTimeType rtt,bool isContinuousSend,DatagramSequenceNumberType sequenceNumber)626 void CCRakNetUDT::UpdateWindowSizeAndAckOnAckPerSyn(CCTimeType curTime, CCTimeType rtt, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber)
627 {
628 (void) curTime;
629 (void) sequenceNumber;
630 if (isContinuousSend==false)
631 {
632 nextCongestionControlBlock=nextDatagramSequenceNumber;
633 pingsLastInterval.Clear(__FILE__,__LINE__);
634 return;
635 }
636
637 pingsLastInterval.Push(rtt,__FILE__,__LINE__);
638 static const int intervalSize=33; // Should be odd
639 if (pingsLastInterval.Size()>intervalSize)
640 pingsLastInterval.Pop();
641 if (GreaterThan(sequenceNumber, nextCongestionControlBlock) &&
642 sequenceNumber-nextCongestionControlBlock>=intervalSize &&
643 pingsLastInterval.Size()==intervalSize)
644 {
645 double slopeSum=0.0;
646 double average=(double) pingsLastInterval[0];
647 int sampleSize=pingsLastInterval.Size();
648 for (int i=1; i < sampleSize; i++)
649 {
650 slopeSum+=(double)pingsLastInterval[i]-(double)pingsLastInterval[i-1];
651 average+=pingsLastInterval[i];
652 }
653 average/=sampleSize;
654
655 if (hadPacketlossThisBlock==true)
656 {
657 }
658 else if (slopeSum < -.10*average)
659 {
660 // Logging
661 // printf("Ping dropping. slope=%f%%. Rate=%f MBPS. Rtt=%i\n", 100.0*slopeSum/average, GetLocalSendRate(), rtt );
662 }
663 else if (slopeSum > .10*average)
664 {
665 // Logging
666 // printf("Ping rising. slope=%f%%. Rate=%f MBPS. Rtt=%i\n", 100.0*slopeSum/average, GetLocalSendRate(), rtt );
667 IncreaseTimeBetweenSends();
668 }
669 else
670 {
671 // Logging
672 // printf("Ping stable. slope=%f%%. Rate=%f MBPS. Rtt=%i\n", 100.0*slopeSum/average, GetLocalSendRate(), rtt );
673
674 // No packetloss over time threshhold, and rtt decreased, so send faster
675 lastRttOnIncreaseSendRate=rtt;
676 DecreaseTimeBetweenSends();
677 }
678
679 pingsLastInterval.Clear(__FILE__,__LINE__);
680 hadPacketlossThisBlock=false;
681 nextCongestionControlBlock=nextDatagramSequenceNumber;
682 }
683
684 lastRtt=rtt;
685 }
686
687 // ----------------------------------------------------------------------------------------------------------------------------
BytesPerMicrosecondToPacketsPerMillisecond(BytesPerMicrosecond in)688 double CCRakNetUDT::BytesPerMicrosecondToPacketsPerMillisecond(BytesPerMicrosecond in)
689 {
690 #if CC_TIME_TYPE_BYTES==4
691 const BytesPerMicrosecond factor = 1.0 / (BytesPerMicrosecond) MAXIMUM_MTU_INCLUDING_UDP_HEADER;
692 #else
693 const BytesPerMicrosecond factor = 1000.0 / (BytesPerMicrosecond) MAXIMUM_MTU_INCLUDING_UDP_HEADER;
694 #endif
695 return in * factor;
696 }
697 // ----------------------------------------------------------------------------------------------------------------------------
InitPacketArrivalHistory(void)698 void CCRakNetUDT::InitPacketArrivalHistory(void)
699 {
700 unsigned int i;
701 for (i=0; i < CC_RAKNET_UDT_PACKET_HISTORY_LENGTH; i++)
702 {
703 packetArrivalHistory[i]=UNDEFINED_TRANSFER_RATE;
704 packetArrivalHistoryContinuousGaps[i]=0;
705 }
706
707 packetArrivalHistoryWriteCount=0;
708 continuousBytesReceived=0;
709 continuousBytesReceivedStartTime=0;
710 }
711 // ----------------------------------------------------------------------------------------------------------------------------
PrintLowBandwidthWarning(void)712 void CCRakNetUDT::PrintLowBandwidthWarning(void)
713 {
714
715 /*
716 printf("\n-------LOW BANDWIDTH -----\n");
717 if (isInSlowStart==false)
718 printf("SND=%f Megabytes per second\n", 1.0/SND);
719 printf("Window size=%f\n", CWND);
720 printf("Pipe from packet pair = %f megabytes per second\n", B);
721 printf("RTT=%f milliseconds\n", RTT/1000.0);
722 printf("RTT Variance=%f milliseconds\n", RTTVar/1000.0);
723 printf("Retransmission=%i milliseconds\n", GetRTOForRetransmission()/1000);
724 printf("Packet arrival rate on the remote system=%f megabytes per second\n", AS);
725 printf("Packet arrival rate on our system=%f megabytes per second\n", ReceiverCalculateDataArrivalRate());
726 printf("isInSlowStart=%i\n", isInSlowStart);
727 printf("---------------\n");
728 */
729 }
GetLocalReceiveRate(CCTimeType currentTime) const730 BytesPerMicrosecond CCRakNetUDT::GetLocalReceiveRate(CCTimeType currentTime) const
731 {
732 return ReceiverCalculateDataArrivalRate(currentTime);
733 }
GetRTT(void) const734 double CCRakNetUDT::GetRTT(void) const
735 {
736 if (RTT==UNSET_TIME_US)
737 return 0.0;
738 return RTT;
739 }
CapMinSnd(const char * file,int line)740 void CCRakNetUDT::CapMinSnd(const char *file, int line)
741 {
742 (void) file;
743 (void) line;
744
745 if (SND > 500)
746 {
747 SND=500;
748 CC_DEBUG_PRINTF_3("%s:%i LIKELY BUG: SND has gotten below 500 microseconds between messages (28.8 modem)\nReport to rakkar@jenkinssoftware.com with file and line number\n", file, line);
749 }
750 }
IncreaseTimeBetweenSends(void)751 void CCRakNetUDT::IncreaseTimeBetweenSends(void)
752 {
753 // In order to converge, bigger numbers have to increase slower and decrease faster
754 // SND==500 then increment is .02
755 // SND==0 then increment is near 0
756 // (SND+1.0) brings it to the range of 1 to 501
757 // Square the number, which is the range of 1 to 251001
758 // Divide by 251001, which is the range of 1/251001 to 1
759
760 double increment;
761 increment = .02 * ((SND+1.0) * (SND+1.0)) / (501.0*501.0) ;
762 // SND=500 then increment=.02
763 // SND=0 then increment=near 0
764 SND*=(1.02 - increment);
765
766 // SND=0 then fast increase, slow decrease
767 // SND=500 then slow increase, fast decrease
768 CapMinSnd(__FILE__,__LINE__);
769 }
DecreaseTimeBetweenSends(void)770 void CCRakNetUDT::DecreaseTimeBetweenSends(void)
771 {
772 double increment;
773 increment = .01 * ((SND+1.0) * (SND+1.0)) / (501.0*501.0) ;
774 // SND=500 then increment=.01
775 // SND=0 then increment=near 0
776 SND*=(.99 - increment);
777 }
778 /*
779 void CCRakNetUDT::SetTimeBetweenSendsLimit(unsigned int bitsPerSecond)
780 {
781 // bitsPerSecond / 1000000 = bitsPerMicrosecond
782 // bitsPerMicrosecond / 8 = BytesPerMicrosecond
783 // 1 / BytesPerMicrosecond = MicrosecondsPerByte
784 // 1 / ( (bitsPerSecond / 1000000) / 8 ) =
785 // 1 / (bitsPerSecond / 8000000) =
786 // 8000000 / bitsPerSecond
787
788 #if CC_TIME_TYPE_BYTES==4
789 MicrosecondsPerByte limit = (MicrosecondsPerByte) 8000 / (MicrosecondsPerByte)bitsPerSecond;
790 #else
791 MicrosecondsPerByte limit = (MicrosecondsPerByte) 8000000 / (MicrosecondsPerByte)bitsPerSecond;
792 #endif
793 if (limit > SND)
794 SND=limit;
795 }
796 */
797
798 #endif