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