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