1 /*
2 http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html
3 
4 cwnd=max bytes allowed on wire at once
5 
6 Start:
7 cwnd=mtu
8 ssthresh=unlimited
9 
10 Slow start:
11 On ack cwnd*=2
12 
13 congestion avoidance:
14 On ack during new period
15 cwnd+=mtu*mtu/cwnd
16 
17 on loss or duplicate ack during period:
18 sshtresh=cwnd/2
19 cwnd=MTU
20 This reenters slow start
21 
22 If cwnd < ssthresh, then use slow start
23 else use congestion avoidance
24 
25 
26 */
27 
28 #include "RakNetDefines.h"
29 
30 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
31 
32 #ifndef __CONGESTION_CONTROL_SLIDING_WINDOW_H
33 #define __CONGESTION_CONTROL_SLIDING_WINDOW_H
34 
35 #include "NativeTypes.h"
36 #include "RakNetTime.h"
37 #include "RakNetTypes.h"
38 #include "DS_Queue.h"
39 
40 /// Sizeof an UDP header in byte
41 #define UDP_HEADER_SIZE 28
42 
43 #define CC_DEBUG_PRINTF_1(x)
44 #define CC_DEBUG_PRINTF_2(x,y)
45 #define CC_DEBUG_PRINTF_3(x,y,z)
46 #define CC_DEBUG_PRINTF_4(x,y,z,a)
47 #define CC_DEBUG_PRINTF_5(x,y,z,a,b)
48 //#define CC_DEBUG_PRINTF_1(x) printf(x)
49 //#define CC_DEBUG_PRINTF_2(x,y) printf(x,y)
50 //#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z)
51 //#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a)
52 //#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b)
53 
54 /// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
55 #define CC_TIME_TYPE_BYTES 8
56 
57 #if CC_TIME_TYPE_BYTES==8
58 typedef RakNetTimeUS CCTimeType;
59 #else
60 typedef RakNetTimeMS CCTimeType;
61 #endif
62 typedef uint24_t DatagramSequenceNumberType;
63 typedef double BytesPerMicrosecond;
64 typedef double BytesPerSecond;
65 typedef double MicrosecondsPerByte;
66 
67 namespace RakNet
68 {
69 
70 class CCRakNetSlidingWindow
71 {
72 	public:
73 
74 	CCRakNetSlidingWindow();
75 	~CCRakNetSlidingWindow();
76 
77 	/// Reset all variables to their initial states, for a new connection
78 	void Init(CCTimeType curTime, uint32_t maxDatagramPayload);
79 
80 	/// Update over time
81 	void Update(CCTimeType curTime, bool hasDataToSendOrResend);
82 
83 	int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
84 	int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
85 
86 	/// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time
87 	/// This reduces overall bandwidth usage
88 	/// How long they can be buffered depends on the retransmit time of the sender
89 	/// Should call once per update tick, and send if needed
90 	bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick);
91 
92 	/// Every data packet sent must contain a sequence number
93 	/// Call this function to get it. The sequence number is passed into OnGotPacketPair()
94 	DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void);
95 	DatagramSequenceNumberType GetNextDatagramSequenceNumber(void);
96 
97 	/// Call this when you send packets
98 	/// Every 15th and 16th packets should be sent as a packet pair if possible
99 	/// When packets marked as a packet pair arrive, pass to OnGotPacketPair()
100 	/// When any packets arrive, (additionally) pass to OnGotPacket
101 	/// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck()
102 	void OnSendBytes(CCTimeType curTime, uint32_t numBytes);
103 
104 	/// Call this when you get a packet pair
105 	void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime);
106 
107 	/// Call this when you get a packet (including packet pairs)
108 	/// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero
109 	/// In that case, send a NAK for every sequence number up to that count
110 	bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount);
111 
112 	/// Call when you get a NAK, with the sequence number of the lost message
113 	/// Affects the congestion control
114 	void OnResend(CCTimeType curTime);
115 	void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber);
116 
117 	/// Call this when an ACK arrives.
118 	/// hasBAndAS are possibly written with the ack, see OnSendAck()
119 	/// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn
120 	/// B and AS are updated at most once per SYN
121 	void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber );
122 	void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber );
123 
124 	/// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted
125 	/// Call before calling OnSendAck()
126 	void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS);
127 
128 	/// Call when we send an ack, to write B and AS if needed
129 	/// B and AS are only written once per SYN, to prevent slow calculations
130 	/// Also updates SND, the period between sends, since data is written out
131 	/// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes
132 	void OnSendAck(CCTimeType curTime, uint32_t numBytes);
133 
134 	/// Call when we send a NACK
135 	/// Also updates SND, the period between sends, since data is written out
136 	void OnSendNACK(CCTimeType curTime, uint32_t numBytes);
137 
138 	/// Retransmission time out for the sender
139 	/// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control
140 	/// RTO = (RTT + 4 * RTTVar) + SYN
141 	/// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2;
142 	/// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED
143 	/// Minimum value is 100 milliseconds
144 	CCTimeType GetRTOForRetransmission(void) const;
145 
146 	/// Set the maximum amount of data that can be sent in one datagram
147 	/// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE
148 	void SetMTU(uint32_t bytes);
149 
150 	/// Return what was set by SetMTU()
151 	uint32_t GetMTU(void) const;
152 
153 	/// Query for statistics
GetLocalSendRate(void)154 	BytesPerMicrosecond GetLocalSendRate(void) const {0;}
155 	BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const;
GetRemoveReceiveRate(void)156 	BytesPerMicrosecond GetRemoveReceiveRate(void) const {0;}
157 	//BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;}
GetEstimatedBandwidth(void)158 	BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;}
GetLinkCapacityBytesPerSecond(void)159 	double GetLinkCapacityBytesPerSecond(void) const {return 0;};
160 
161 	/// Query for statistics
162 	double GetRTT(void) const;
163 
GetIsInSlowStart(void)164 	bool GetIsInSlowStart(void) const {return IsInSlowStart();}
GetCWNDLimit(void)165 	uint32_t GetCWNDLimit(void) const {return (uint32_t) 0;}
166 
167 
168 	/// Is a > b, accounting for variable overflow?
169 	static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
170 	/// Is a < b, accounting for variable overflow?
171 	static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
172 //	void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond);
173 	uint64_t GetBytesPerSecondLimitByCongestionControl(void) const;
174 
175 	void OnExternalPing(double pingMS);
176 
177 	protected:
178 
179 	// Maximum amount of bytes that the user can send, e.g. the size of one full datagram
180 	uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER;
181 
182 	double RTT;
183 
184 	double cwnd; // max bytes on wire
185 	double ssThresh; // Threshhold between slow start and congestion avoidance
186 
187 	/// When we get an ack, if oldestUnsentAck==0, set it to the current time
188 	/// When we send out acks, set oldestUnsentAck to 0
189 	CCTimeType oldestUnsentAck;
190 
191 	CCTimeType GetSenderRTOForACK(void) const;
192 
193 	/// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment
194 	DatagramSequenceNumberType nextDatagramSequenceNumber;
195 	DatagramSequenceNumberType nextCongestionControlBlock;
196 	bool backoffThisBlock, speedUpThisBlock;
197 	/// Track which datagram sequence numbers have arrived.
198 	/// If a sequence number is skipped, send a NAK for all skipped messages
199 	DatagramSequenceNumberType expectedNextSequenceNumber;
200 
201 	bool _isContinuousSend;
202 
203 	bool IsInSlowStart(void) const;
204 };
205 
206 }
207 
208 #endif
209 
210 #endif
211 
212