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