internal void OnICMPError(RUDPOutgoingPacket packet) { int errorMTU = packet.Payload.Length + RUDPStack.UDPHeaderLength + RUDPStack.RUDPHeaderLength; int nextMTU = (int)(errorMTU * 0.75); nextMTU = Math.Min(Math.Max(Math.Max(MinMTU, nextMTU), _rudp._mtu), MaxMTU); Trace("MTU:OnICMPError:" + errorMTU + " -> " + nextMTU); //---- We have a result for the packet _lastProbeTS = -1; _mtuProbeResendCount = 0; //---- User packet : URGENT if (packet.Channel == RUDPPacketChannel.UserPacket) { _rudp._mtu = nextMTU; SendProbe(_rudp._mtu); return; } //---- MTU probe if (packet.Channel == RUDPPacketChannel.MTUTuning) { if (errorMTU > _rudp._mtu && nextMTU < _rudp._mtu) { nextMTU = _rudp._mtu; } nextMTU = Math.Min(Math.Max(MinMTU, nextMTU), MaxMTU); SendDelayedProbe(nextMTU, DefaultProbeInterval); return; } }
/// <summary> /// Called when a packet is resended /// </summary> internal void OnTimeOut(RUDPOutgoingPacket packet) { //---- Congestion lock (this) { OnTimeOut_UpdateParameters(packet); OnTimeOut_UpdateWindow(); } }
internal void OnTimeOut_UpdateParameters(RUDPOutgoingPacket packet) { // Karn's Algorithm : On successive retransmissions, set each timeout to twice the previous one. if (packet.Retransmission > 0) { //-- Calculate _rto #if TRACE_MEMORY traces.Add("RTO x 2 : " + _rudp._rto + " new : " + _rudp._rto * 2); #endif // Exponential RTO Backoff process _rudp.RTO = Math.Min(_rudp.RTO * 2, 60000000); //-- Calculate _sto _rudp.STO = (int)(15000000 + 4 * _rudp.RTT); } }
internal void OnACK_UpdateParameters(RUDPOutgoingPacket packet, double currentRTT) { //---- TCP - (RFC 2988) : http://www.faqs.org/rfcs/rfc2988.html if (packet.Retransmission > 0) { return; } double rudpRTT; double rudpDeltaRTT; //-- Calculate _rtt if (_rudp._rtt == 0) { rudpRTT = currentRTT; rudpDeltaRTT = currentRTT / 2; } else { rudpRTT = _rudp.RTT; rudpDeltaRTT = _rudp.DeltaRTT; // Jacobson's algorithm rudpRTT = (0.875 * rudpRTT + 0.125 * currentRTT); double error = currentRTT - rudpRTT; rudpDeltaRTT = (0.75 * rudpDeltaRTT + 0.25 * Math.Abs(error)); } //-- Calculate _rto #if TRACE_MEMORY traces.Add("RTO ACK : " + _rudp._rto + " new : " + _rudp._rtt + Math.Max(1, 4 * _rudp._deltaRtt) + "RTT=" + _rudp._rtt); #endif double Rto = rudpRTT + Math.Max(4, 4 * rudpDeltaRTT); //if (_rudp._rto < 1000000) // _rudp._rto = 1000000; if (Rto > 60000000) { Rto = 60000000; } //-- Calculate _sto long Sto = (long)(15000000 + 4 * rudpRTT); //-- Update parameters _rudp.SetRTT(rudpRTT, rudpDeltaRTT, Rto, Sto); }
abstract internal void OnACK_UpdateWindow(RUDPOutgoingPacket packet);
internal void OnACK_UpdateParameters(RUDPOutgoingPacket packet, double currentRTT) { //---- TCP - (RFC 2988) : http://www.faqs.org/rfcs/rfc2988.html if (packet.Retransmission > 0) return; double rudpRTT; double rudpDeltaRTT; //-- Calculate _rtt if (_rudp._rtt == 0) { rudpRTT = currentRTT; rudpDeltaRTT = currentRTT / 2; } else { rudpRTT = _rudp.RTT; rudpDeltaRTT = _rudp.DeltaRTT; // Jacobson's algorithm rudpRTT = (0.875 * rudpRTT + 0.125 * currentRTT); double error = currentRTT - rudpRTT; rudpDeltaRTT = (0.75 * rudpDeltaRTT + 0.25 * Math.Abs(error)); } //-- Calculate _rto #if TRACE_MEMORY traces.Add("RTO ACK : " + _rudp._rto + " new : " + _rudp._rtt + Math.Max(1, 4 * _rudp._deltaRtt) + "RTT=" + _rudp._rtt); #endif double Rto = rudpRTT + Math.Max(4, 4 * rudpDeltaRTT); //if (_rudp._rto < 1000000) // _rudp._rto = 1000000; if (Rto > 60000000) Rto = 60000000; //-- Calculate _sto long Sto = (long)(15000000 + 4 * rudpRTT); //-- Update parameters _rudp.SetRTT(rudpRTT, rudpDeltaRTT, Rto, Sto); }
internal void OnACK(RUDPOutgoingPacket packet, double currentRTT) { // Duplicated ACK if (packet == null) return; FlightSize -= packet.Payload.Length + RUDPStack.UDPHeaderLength; //---- Congestion lock (this) { OnACK_UpdateParameters(packet, currentRTT); OnACK_UpdateWindow(packet); } //---- Sliding int packetId = packet.PacketId; _sendSlotsLock.EnterWriteLock(); SWSlot slot = null; try { for (int index = 0; index < _sendSlots.Count; index++) { slot = _sendSlots[index]; // Delete this slot if (slot.EndPacketId < 0 && slot.StartPacketId == packetId) { _sendSlots.RemoveAt(index); return; } // Decrease the slot if (slot.EndPacketId > -1 && slot.StartPacketId == packetId) { slot.StartPacketId++; slot.StartByte += packet.Payload.Length; if (slot.StartPacketId == slot.EndPacketId) slot.EndPacketId = -1; return; } // Decrease the slot if (slot.EndPacketId > -1 && slot.EndPacketId == packetId) { slot.EndPacketId--; slot.EndByte -= packet.Payload.Length; if (slot.StartPacketId == slot.EndPacketId) slot.EndPacketId = -1; return; } // Split the slot if (slot.EndPacketId > -1 && slot.StartPacketId <= packetId && slot.EndPacketId >= packetId) { // Right slot SWSlot newSlot = new SWSlot(packetId + 1, slot.EndPacketId, packet.Sequence + packet.Payload.Length + 1, slot.EndByte); if (newSlot.StartPacketId == newSlot.EndPacketId) newSlot.EndPacketId = -1; _sendSlots.Insert(index + 1, newSlot); // Left slot slot.EndPacketId = packetId - 1; slot.EndByte = packet.Sequence - 1; if (slot.StartPacketId == slot.EndPacketId) slot.EndPacketId = -1; return; } } } finally { _sendSlotsLock.ExitWriteLock(); ResumeTransmission(); } }
internal void OnICMPError(RUDPOutgoingPacket packet) { int errorMTU = packet.Payload.Length + RUDPStack.UDPHeaderLength + RUDPStack.RUDPHeaderLength; int nextMTU = (int)(errorMTU * 0.75); nextMTU = Math.Min(Math.Max(Math.Max(MinMTU, nextMTU),_rudp._mtu), MaxMTU); Trace("MTU:OnICMPError:" + errorMTU + " -> " + nextMTU); //---- We have a result for the packet _lastProbeTS = -1; _mtuProbeResendCount = 0; //---- User packet : URGENT if (packet.Channel == RUDPPacketChannel.UserPacket) { _rudp._mtu = nextMTU; SendProbe(_rudp._mtu); return; } //---- MTU probe if (packet.Channel == RUDPPacketChannel.MTUTuning) { if (errorMTU > _rudp._mtu && nextMTU < _rudp._mtu) nextMTU = _rudp._mtu; nextMTU = Math.Min(Math.Max(MinMTU, nextMTU), MaxMTU); SendDelayedProbe(nextMTU, DefaultProbeInterval); return; } }
private static bool SocketSendPacket(RUDPSocket rudp, RUDPOutgoingPacket packet, byte[] rudpPayload, long now) { //---- Send the request try { rudp._physical._socket.SendTo(rudpPayload, rudp._remoteEndPoint); //rudp._physical._socket.BeginSendTo(rudpPayload, 0, rudpPayload.Length, SocketFlags.None, rudp._remoteEndPoint, null, null); } catch (SocketException exception) { if (exception.ErrorCode == (int)SocketError.MessageSize && packet.Channel == RUDPPacketChannel.MTUTuning) { // ICMP type 3 subtype 4 // ICMP message, tell that this packet is too big rudp._pmtuDiscovery.OnICMPError(packet); return true; } OnSocketUnhandledError(rudp, SocketErrorToRUDPSocketError(exception.SocketErrorCode), null); return false; } rudp._lastSendTS = now; packet.TSLastSend = now; return true; }
internal static void ReleaseOutgoingPacket(RUDPOutgoingPacket packet) { //return; _outgoingPacketsPools.Enqueue(packet); PayloadManager.Deallocate(packet.Channel, packet.Payload); packet.Payload = null; }
private static void SetPacketACKed(RUDPSocket rudp, RUDPOutgoingPacket packet, double currentRTT) { lock (packet) { if (packet.IsACKed) return; rudp._controlWindow.OnACK(packet, currentRTT); // Mark as ACKed packet.IsACKed = true; } Trace("Packet ACKed(" + rudp.Handle + "): " + packet.PacketId + " " + packet.Channel); //---- Ping ACK if ((packet.Channel == RUDPPacketChannel.Ping || packet.Channel == RUDPPacketChannel.PingRendezVous) && rudp._status == RUDPSocketStatus.Connecting) { rudp._status = RUDPSocketStatus.Connected; // MTU tuning if (rudp._usePMTUDiscovery) rudp._pmtuDiscovery.StartTuning(); // connection done rudp.OnEndConnect(RUDPSocketError.Success); return; } //---- Tear Down ACK : It was a tear down message, it has been received, we can close if (packet.Channel == RUDPPacketChannel.TearDown && rudp._status == RUDPSocketStatus.Closing) { rudp._status = RUDPSocketStatus.ClosingACKed; // Remove it to our list of "connected" sockets if (rudp._remoteEndPoint != null) { // Unregister for the stack UnregisterRUDPSocket(rudp); rudp._physical.UnregisterConnectedSocket(rudp); } } }
internal void OnACK(RUDPOutgoingPacket packet, double currentRTT) { // Duplicated ACK if (packet == null) { return; } FlightSize -= packet.Payload.Length + RUDPStack.UDPHeaderLength; //---- Congestion lock (this) { OnACK_UpdateParameters(packet, currentRTT); OnACK_UpdateWindow(packet); } //---- Sliding int packetId = packet.PacketId; _sendSlotsLock.EnterWriteLock(); SWSlot slot = null; try { for (int index = 0; index < _sendSlots.Count; index++) { slot = _sendSlots[index]; // Delete this slot if (slot.EndPacketId < 0 && slot.StartPacketId == packetId) { _sendSlots.RemoveAt(index); return; } // Decrease the slot if (slot.EndPacketId > -1 && slot.StartPacketId == packetId) { slot.StartPacketId++; slot.StartByte += packet.Payload.Length; if (slot.StartPacketId == slot.EndPacketId) { slot.EndPacketId = -1; } return; } // Decrease the slot if (slot.EndPacketId > -1 && slot.EndPacketId == packetId) { slot.EndPacketId--; slot.EndByte -= packet.Payload.Length; if (slot.StartPacketId == slot.EndPacketId) { slot.EndPacketId = -1; } return; } // Split the slot if (slot.EndPacketId > -1 && slot.StartPacketId <= packetId && slot.EndPacketId >= packetId) { // Right slot SWSlot newSlot = new SWSlot(packetId + 1, slot.EndPacketId, packet.Sequence + packet.Payload.Length + 1, slot.EndByte); if (newSlot.StartPacketId == newSlot.EndPacketId) { newSlot.EndPacketId = -1; } _sendSlots.Insert(index + 1, newSlot); // Left slot slot.EndPacketId = packetId - 1; slot.EndByte = packet.Sequence - 1; if (slot.StartPacketId == slot.EndPacketId) { slot.EndPacketId = -1; } return; } } } finally { _sendSlotsLock.ExitWriteLock(); ResumeTransmission(); } }