예제 #1
0
        /// <summary>
        /// Used when "resending" or sending queued "ACKs"
        /// </summary>
        internal List <SACKSlot> PrepareACKList()
        {
            List <SACKSlot> list = new List <SACKSlot>();

            lock (this)
            {
                //---- Add all the slots, except the first one
                for (int index = 1; index < _slots.Count; index++)
                {
                    SACKSlot slot = _slots[index];
                    if (slot.ACKsCount > 0)
                    {
                        slot.ACKsCount = 0;
                        list.Add(slot.Clone());
                    }
                }

                //---- Add the first slot
                // Useful when some ACKs are loosed
                if (_slots[0].StartPacketId > -1)
                {
                    if (list.Count > 1 || _slots[0].ACKsCount > 0)
                    {
                        _slots[0].ACKsCount = 0;
                        list.Insert(0, _slots[0].Clone());
                    }
                }

                Interlocked.Exchange(ref _acksCount, 0);
            }

            CheckACKCount();

            return(list);
        }
예제 #2
0
        internal SACKWindow()
        {
            SACKSlot slot = new SACKSlot(-1, -1);

            slot.ACKsCount = 0;
            _slots.Add(slot);
        }
예제 #3
0
        /// <summary>
        /// Used when sending a packet.
        /// </summary>
        internal void GetSLACKSlots(out SACKSlot slot1, out SACKSlot slot2, out SACKSlot slot3, out SACKSlot slot4)
        {
            slot1 = null;
            slot2 = null;
            slot3 = null;
            slot4 = null;

            lock (this)
            {
                if (_slots[0].StartPacketId < 0)
                {
                    return;
                }

                //---- Useful when some ACKs are loosed
                slot1 = _slots[0].Clone();
                _slots[0].ACKsCount = 0;
                Interlocked.Exchange(ref _acksCount, _acksCount - slot1.ACKsCount);

                CheckACKCount();

                //---- Add all the slots
                for (int index = 1; index < _slots.Count; index++)
                {
                    SACKSlot slot = _slots[index];
                    if (slot.ACKsCount > 0)
                    {
                        Interlocked.Exchange(ref _acksCount, _acksCount - slot.ACKsCount);
                        slot.ACKsCount = 0;

                        CheckACKCount();

                        if (slot2 == null)
                        {
                            slot2 = slot.Clone();
                        }
                        else if (slot3 == null)
                        {
                            slot3 = slot.Clone();
                        }
                        else if (slot4 == null)
                        {
                            slot4 = slot.Clone();
                            return;
                        }
                    }
                }
            }
        }
예제 #4
0
        internal void OnReceivePacket(int packetId)
        {
            RUDPStack.Trace("SACK OnReceivePacket:" + packetId);

            Monitor.Enter(this);
            try
            {
                SACKSlot slot;
                SACKSlot newSlot;
                for (int index = 0; index < _slots.Count; index++)
                {
                    slot = _slots[index];

                    //-- Already in the slot
                    if (packetId >= slot.StartPacketId && packetId <= slot.EndPacketId)
                    {
                        slot.ACKsCount++;
                        return;
                    }

                    //-- Grow the slot
                    if (slot.EndPacketId + 1 == packetId)
                    {
                        slot.EndPacketId++;
                        slot.ACKsCount++;

                        // First packet
                        if (slot.StartPacketId < 0)
                        {
                            slot.StartPacketId = 0;
                        }

                        // Merge with next
                        if ((index + 1) < _slots.Count && (slot.EndPacketId + 1) == _slots[index + 1].StartPacketId)
                        {
                            index++;
                            slot.EndPacketId = _slots[index].EndPacketId;
                            slot.ACKsCount  += _slots[index].ACKsCount;

                            _slots.RemoveAt(index);
                        }

                        return;
                    }

                    //-- Before this slot (and then after previous one !)
                    if (packetId < slot.StartPacketId)
                    {
                        if (packetId == slot.StartPacketId - 1)
                        {
                            slot.StartPacketId--;
                            slot.ACKsCount++;
                        }
                        else
                        {
                            newSlot = new SACKSlot(packetId, packetId);
                            _slots.Insert(index, newSlot);
                        }

                        return;
                    }
                }

                //-- New slot at the end
                newSlot = new SACKSlot(packetId, packetId);
                _slots.Add(newSlot);
            }
            finally
            {
                Interlocked.Increment(ref _acksCount);
                Monitor.Exit(this);
                CheckACKCount();
            }
        }
예제 #5
0
		/// <summary>
		/// Handle the bytes received from a socket.
		/// </summary>
		private static void HandlePayload(PhysicalSocket physical, byte[] payload, int length, IPEndPoint sender,
				out RUDPPacketChannel channel,
				out int packetId,
				out int advertisedWindowSize,
				out SACKSlot slot1,
				out SACKSlot slot2,
				out SACKSlot slot3,
				out SACKSlot slot4,
				out byte[] packetPayload)
		{
			int offset = 0;

			//-- Protocol version
			byte version = payload[offset];
			offset++;

			//-- Header information
			byte sacksSlotCount = payload[offset];
			offset++;

			//-- Channel
			byte channelByte = payload[offset];
			offset++;
			switch (channelByte)
			{
				case 0:
					channel = RUDPPacketChannel.Undefined;
					break;
				case 10:
					channel = RUDPPacketChannel.Ping;
					break;
				case 20:
					channel = RUDPPacketChannel.PingRendezVous;
					break;
				case 30:
					channel = RUDPPacketChannel.TearDown;
					break;
				case 40:
					channel = RUDPPacketChannel.UserPacket;
					break;
				case 50:
					channel = RUDPPacketChannel.ACK;
					break;
				case 70:
					channel = RUDPPacketChannel.OutOfOrder;
					break;
				case 100:
					channel = RUDPPacketChannel.KeepAlive;
					break;
				case 120:
					channel = RUDPPacketChannel.MTUTuning;
					break;
				case 121:
					channel = RUDPPacketChannel.MTUTuningACK;
					break;
				case 150:
					channel = RUDPPacketChannel.Bandwidth01;
					break;
				case 151:
					channel = RUDPPacketChannel.BandwidthResponse01;
					break;
				case 155:
					channel = RUDPPacketChannel.Bandwidth02;
					break;
				case 156:
					channel = RUDPPacketChannel.BandwidthResponse02;
					break;
				default:
					throw new Exception("Unsupported channel type");
			}

			//-- Packet Id
			packetId = BinaryHelper.ReadInt(payload, offset);
			offset += 4;

			//-- Control information : Advertised window
			advertisedWindowSize = BinaryHelper.ReadInt(payload, offset);
			offset += 4;

			//-- Payload length
			int payloadLength = BinaryHelper.ReadInt(payload, offset);
			offset += 4;

			//---- SACK Slots
			slot1 = null;
			slot2 = null;
			slot3 = null;
			slot4 = null;
			int startPacketId;
			int endPacketId;
			if (sacksSlotCount > 0)
			{
				startPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				endPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				slot1 = new SACKSlot(startPacketId, endPacketId);
			}
			else offset += 8;
			if (sacksSlotCount > 1)
			{
				startPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				endPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				slot2 = new SACKSlot(startPacketId, endPacketId);
			}
			else offset += 8;
			if (sacksSlotCount > 2)
			{
				startPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				endPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				slot3 = new SACKSlot(startPacketId, endPacketId);
			}
			else offset += 8;
			if (sacksSlotCount > 3)
			{
				startPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				endPacketId = BinaryHelper.ReadInt(payload, offset);
				offset += 4;
				slot4 = new SACKSlot(startPacketId, endPacketId);
			}
			else offset += 8;

			//-- Payload
			packetPayload = new byte[payloadLength];
			if (payloadLength > 0)
				Buffer.BlockCopy(payload, offset, packetPayload, 0, payloadLength);
		}
예제 #6
0
		/// <summary>
		/// Create the RUDP packet : HEADER + payload
		/// </summary>
		internal static byte[] MakePacketPayload(RUDPSocket rudp,
												int packetId,
												RUDPPacketChannel channel,
												SACKSlot slot1, SACKSlot slot2, SACKSlot slot3, SACKSlot slot4,
												byte[] payload,
												int offset,
												int payloadLength)
		{
			//---- Here we make the payload while we will send:
			/**
			 * We create a header
			 * The format is:
			 * --------------
			 * - 1 byte : protocol version
			 * - 1 byte : header information
			 * - 1 byte : channel
			 * - 4 bytes : message ID
			 * - 4 bytes : advertized congestion window size
			 * - 4 bytes : payloadLength
			 * - 4 X (4 + 4) : 32 bytes for 4 SACK slots
			 * - the payload bytes
			 */
			int headerOffset = 0;
			byte[] packetPayload = PayloadManager.Allocate(channel, RUDPHeaderLength + payloadLength);

			//---- Protocol version
			packetPayload[headerOffset] = (byte)1;
			headerOffset++;

			//---- Header information
			// 3 bits : number of ACK slots

			// sack slot (3 bits)
			byte sacksSlotCount = 0;
			if (slot1 != null)
				sacksSlotCount++;
			if (slot2 != null)
				sacksSlotCount++;
			if (slot3 != null)
				sacksSlotCount++;
			if (slot4 != null)
				sacksSlotCount++;

			packetPayload[headerOffset] = 0; // Reset (Because buffer reused)
			packetPayload[headerOffset] |= sacksSlotCount;
			headerOffset++;

			//---- Channel
			packetPayload[headerOffset] = (byte)channel;
			headerOffset++;

			//---- Message Id
			BinaryHelper.WriteInt(packetId, packetPayload, headerOffset);
			headerOffset += 4;

			//---- Control information : Advertised window
			if (rudp == null)
				BinaryHelper.WriteInt(-1, packetPayload, headerOffset);
			else
				BinaryHelper.WriteInt((int)rudp._controlWindow.AdvertisedWindow, packetPayload, headerOffset);
			headerOffset += 4;

			//---- Payload length
			BinaryHelper.WriteInt(payloadLength, packetPayload, headerOffset);
			headerOffset += 4;

			//---- SACK Slots
			if (slot1 != null)
			{
				BinaryHelper.WriteInt(slot1.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot1.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else
			{
				// Reset (Because buffer reused)
				Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8);
				headerOffset += 8;
			}
			if (slot2 != null)
			{
				BinaryHelper.WriteInt(slot2.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot2.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else
			{
				// Reset (Because buffer reused)
				Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8);
				headerOffset += 8;
			}
			if (slot3 != null)
			{
				BinaryHelper.WriteInt(slot3.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot3.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else
			{
				// Reset (Because buffer reused)
				Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8);
				headerOffset += 8;
			}
			if (slot4 != null)
			{
				BinaryHelper.WriteInt(slot4.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot4.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else
			{
				// Reset (Because buffer reused)
				Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8);
				headerOffset += 8;
			}

			if (payload == null)
				return packetPayload;

			//---- Payload
			Buffer.BlockCopy(payload, offset, packetPayload, headerOffset, payloadLength);

			return packetPayload;
		}
예제 #7
0
		static private void UpdatePacketPayload(byte[] packetPayload, SACKSlot slot1, SACKSlot slot2, SACKSlot slot3, SACKSlot slot4)
		{
			//---- Update header
			byte sacksSlotCount = 0;
			if (slot1 != null)
				sacksSlotCount++;
			if (slot2 != null)
				sacksSlotCount++;
			if (slot3 != null)
				sacksSlotCount++;
			if (slot4 != null)
				sacksSlotCount++;

			packetPayload[1] = sacksSlotCount;

			//---- Update slots
			int headerOffset = 15;
			if (slot1 != null)
			{
				BinaryHelper.WriteInt(slot1.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot1.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else headerOffset += 8;
			if (slot2 != null)
			{
				BinaryHelper.WriteInt(slot2.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot2.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else headerOffset += 8;
			if (slot3 != null)
			{
				BinaryHelper.WriteInt(slot3.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot3.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			else headerOffset += 8;
			if (slot4 != null)
			{
				BinaryHelper.WriteInt(slot4.StartPacketId, packetPayload, headerOffset);
				headerOffset += 4;
				BinaryHelper.WriteInt(slot4.EndPacketId, packetPayload, headerOffset);
				headerOffset += 4;
			}
			//else headerOffset += 8;
		}
예제 #8
0
		private static void HandleACKs(RUDPSocket rudp,
										SACKSlot slot1,
										SACKSlot slot2,
										SACKSlot slot3,
										SACKSlot slot4)
		{
			// No ack
			if (slot1 == null)
				return;

			int maxId = slot1.EndPacketId;
			if (slot4 != null)
				maxId = slot4.EndPacketId;
			else if (slot3 != null)
				maxId = slot3.EndPacketId;
			else if (slot2 != null)
				maxId = slot2.EndPacketId;

#if CONSOLE_TRACE
			if (slot1 != null)
				Trace("Handle ACK[1](" + rudp.Handle + "): " + slot1.StartPacketId + " <-> " + slot1.EndPacketId);
			if (slot2 != null)
				Trace("Handle ACK[2](" + rudp.Handle + "): " + slot2.StartPacketId + " <-> " + slot2.EndPacketId);
			if (slot3 != null)
				Trace("Handle ACK[3](" + rudp.Handle + "): " + slot3.StartPacketId + " <-> " + slot3.EndPacketId);
			if (slot4 != null)
				Trace("Handle ACK[4](" + rudp.Handle + "): " + slot4.StartPacketId + " <-> " + slot4.EndPacketId);
#endif

			//---- Prepare the list of packets
			List<RUDPOutgoingPacket> toACKPackets = new List<RUDPOutgoingPacket>();

			RUDPOutgoingPacket lastPacket = null;
			double currentRTT = Double.MaxValue;
			rudp._outgoingPacketsLock.EnterReadLock();

			try
			{
				for (int index = 0; index < rudp._outgoingPackets.Count; index++)
				{
					RUDPOutgoingPacket packet = rudp._outgoingPackets[index];

					if (packet.PacketId > maxId)
						break;

					if (packet.IsACKed)
						continue;

					if (slot4 != null)
						if (packet.PacketId >= slot4.StartPacketId && packet.PacketId <= slot4.EndPacketId)
						{
							if (packet.Retransmission < 1)
							{
								lastPacket = packet;
								currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend);
							}
							toACKPackets.Add(packet);
							continue;
						}

					if (slot3 != null)
						if (packet.PacketId >= slot3.StartPacketId && packet.PacketId <= slot3.EndPacketId)
						{
							if (packet.Retransmission < 1)
							{
								lastPacket = packet;
								currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend);
							}
							toACKPackets.Add(packet);
							continue;
						}

					if (slot2 != null)
						if (packet.PacketId >= slot2.StartPacketId && packet.PacketId <= slot2.EndPacketId)
						{
							if (packet.Retransmission < 1)
							{
								lastPacket = packet;
								currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend);
							}
							toACKPackets.Add(packet);
							continue;
						}

					if (packet.PacketId >= slot1.StartPacketId && packet.PacketId <= slot1.EndPacketId)
					{
						if (packet.Retransmission < 1)
						{
							lastPacket = packet;
							currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend);
						}
						toACKPackets.Add(packet);
					}
				}
			}
			finally
			{
				rudp._outgoingPacketsLock.ExitReadLock();
			}

			//---- If no good packet, use current RTT
			if (lastPacket == null)
				currentRTT = rudp.RTT;

			if (currentRTT < 1)
				currentRTT = 1;

			//---- Set the ACK for all the packets
			for (int index = 0; index < toACKPackets.Count; index++)
			{
				RUDPOutgoingPacket packet = toACKPackets[index];
				SetPacketACKed(rudp, packet, currentRTT);
			}
		}
예제 #9
0
		private static void HandlePacket(PhysicalSocket physical,
										IPEndPoint sender,
										RUDPPacketChannel channel,
										int packetId,
										int advertisedWindowSize,
										SACKSlot slot1, SACKSlot slot2, SACKSlot slot3, SACKSlot slot4,
										byte[] payload)
		{
			RUDPSocket rudp = null;

			//---- PING
			if (channel == RUDPPacketChannel.Ping || channel == RUDPPacketChannel.PingRendezVous)
			{
				rudp = HandlePing(physical, sender, packetId, channel);

				// Do not handle this message
				if (rudp == null)
					return;
			}

			//---- Search the socket
			if (rudp == null)
			{
				physical._connectedRDUPsLock.EnterReadLock();
				physical._connectedRDUPs.TryGetValue(sender, out rudp);
				physical._connectedRDUPsLock.ExitReadLock();
			}

			//---- Direct send of ACK, because socket can be shutdowned and removed
			if (channel == RUDPPacketChannel.TearDown)
			{
				byte[] packetPayload = MakePacketPayload(rudp, -1, RUDPPacketChannel.ACK, new SACKSlot(packetId, packetId), null, null, null, null, 0, 0);
				SocketSendACK(rudp, physical, sender, packetPayload);
				PayloadManager.Deallocate(RUDPPacketChannel.ACK, packetPayload);
			}

			//---- Released socket
			if (rudp == null)
				return;

#if CONSOLE_TRACE
			if (packetId > -1)
				Trace("Handle packet (" + rudp.Handle + ")(" + channel + "):" + packetId);
#endif

			//---- Advertised window
			rudp._controlWindow.OnReceiveAdvertisedWindow(advertisedWindowSize);

			//---- Handle ACKs
			HandleACKs(rudp, slot1, slot2, slot3, slot4);

			if (channel == RUDPPacketChannel.ACK)
				return;

			//---- Non reliable messages
			if (packetId < 0)
			{
				//-- Bandwidth
				if (channel == RUDPPacketChannel.Bandwidth01)
				{
					PushPacketToSend(rudp, false, RUDPPacketChannel.BandwidthResponse01, null, 0, 0);
					return;
				}
				else if (channel == RUDPPacketChannel.Bandwidth02)
				{
					PushPacketToSend(rudp, false, RUDPPacketChannel.BandwidthResponse02, payload, 0, 8);
					return;
				}
				else if (channel == RUDPPacketChannel.BandwidthResponse01)
				{
					rudp._bandwidthResponse01TS = HiResTimer.MicroSeconds;
				}
				else if (channel == RUDPPacketChannel.BandwidthResponse02)
				{
					//---- Calculate bandwidth
					// Bdw (Bytes / milli-sec)
					long now = HiResTimer.MicroSeconds;
					double delay = (now - rudp._bandwidthResponse01TS) / 1000;
					if (delay < 0.001)
						delay = 0.001;

					// Arrival Speed
					double arrivalSpeed = (RUDPHeaderLength + UDPHeaderLength) / delay;

					// RTT
					double currentRtt = (now - BinaryHelper.ReadInt(payload, 0)) / 1000;
					if (currentRtt < 0.001)
						currentRtt = 0.001;

					// BDP = Bandwidth(Byte / Ms) * RTT;
					double bandwidth = (long)(arrivalSpeed * currentRtt);
					rudp._bandwidth = (long)(rudp._bandwidth * 0.875f + bandwidth * 0.125f);
				}

				//-- MTU Tuning
				else if (channel == RUDPPacketChannel.MTUTuning)
				{
					rudp._pmtuDiscovery.OnReceiveProbe(payload.Length);
					return;
				}
				else if (channel == RUDPPacketChannel.MTUTuningACK)
				{
					rudp._pmtuDiscovery.OnReceiveProbeACK(payload);
					return;
				}

				//if ((rudp._incomingNonReliablePackets.Count * rudp._mtu) >= rudp._receiveSize)
				//return;

				RUDPIngoingPacket nonReliablePacket = new RUDPIngoingPacket(rudp, packetId, payload, channel, HiResTimer.MicroSeconds);
				rudp._incomingPackets.AddPacket(nonReliablePacket);

				rudp.HandleNextUserPacket(false);
				return;
			}

			//---- Do not process a duplicated packets
			bool isDuplicatedPacket;
			isDuplicatedPacket = (packetId <= rudp._incomingPackets.CurrentPacketId);
			if (!isDuplicatedPacket)
				isDuplicatedPacket = rudp._incomingPackets.ContainsPacket(packetId);

			//---- Can I receive the packet now ?
			bool canReceive = rudp._controlWindow.CanReceive(packetId, payload.Length);

			//---- Send the ACK
			if (channel != RUDPPacketChannel.Ping && channel != RUDPPacketChannel.PingRendezVous)
				if (canReceive ||	// Can receive, then we send ACK
					(!canReceive && isDuplicatedPacket))	// Is duplicated, then already in the list -> send another ACK
					rudp._sackWindow.OnReceivePacket(packetId);

			//---- Check if we can handle this message
			if (!canReceive || isDuplicatedPacket)
				return;

			//---- If we are not connected, we cannot hanlde messages ! We need a connection before.
			if (rudp._status != RUDPSocketStatus.Connected && channel == RUDPPacketChannel.UserPacket)
				return;

			//---- Check for Out of order packets
			if (rudp._incomingPackets.Count > 0)
			{
				int greaterPacketId = rudp._incomingPackets.LastPacketId;
				if (packetId != greaterPacketId + 1)
				{
					byte[] oooPayload = new byte[8];
					// start packet
					BinaryHelper.WriteInt(greaterPacketId + 1, oooPayload, 0);
					// end packet
					BinaryHelper.WriteInt(packetId - 1, oooPayload, 4);
					PushPacketToSend(rudp, false, RUDPPacketChannel.OutOfOrder, oooPayload, 0, 8);
				}
			}

			//---- Receive Out of order notification
			if (channel == RUDPPacketChannel.OutOfOrder)
			{
				rudp._controlWindow.OnOutOfOrder(BinaryHelper.ReadInt(payload, 0), BinaryHelper.ReadInt(payload, 4));
			}

			//---- TEAR DOWN
			if (channel == RUDPPacketChannel.TearDown)
			{
				// Initiate the close process
				if (rudp._status == RUDPSocketStatus.Connected)
				{
					// Notify control window
					rudp._controlWindow.OnReceive(null);

					// Start shutdown
					AsyncShutdown(rudp);
				}

				return;
			}

			//---- Add the packet to incoming list
			RUDPIngoingPacket packet = new RUDPIngoingPacket(rudp, packetId, payload, channel, HiResTimer.MicroSeconds);

			// Notify control window
			rudp._controlWindow.OnReceive(packet);
			rudp._incomingPackets.AddPacket(packet);

			//------ Handle the ordered ingoing packets
			rudp.HandleNextUserPacket(false);
		}
예제 #10
0
		internal void OnReceivePacket(int packetId)
		{
			RUDPStack.Trace("SACK OnReceivePacket:" + packetId);

			Monitor.Enter(this);
			try
			{
				SACKSlot slot;
				SACKSlot newSlot;
				for (int index = 0; index < _slots.Count; index++)
				{
					slot = _slots[index];

					//-- Already in the slot
					if (packetId >= slot.StartPacketId && packetId <= slot.EndPacketId)
					{
						slot.ACKsCount++;
						return;
					}

					//-- Grow the slot
					if (slot.EndPacketId + 1 == packetId)
					{
						slot.EndPacketId++;
						slot.ACKsCount++;

						// First packet
						if (slot.StartPacketId < 0)
							slot.StartPacketId = 0;

						// Merge with next
						if ((index + 1) < _slots.Count && (slot.EndPacketId + 1) == _slots[index + 1].StartPacketId)
						{
							index++;
							slot.EndPacketId = _slots[index].EndPacketId;
							slot.ACKsCount += _slots[index].ACKsCount;

							_slots.RemoveAt(index);
						}

						return;
					}

					//-- Before this slot (and then after previous one !)
					if (packetId < slot.StartPacketId)
					{
						if (packetId == slot.StartPacketId - 1)
						{
							slot.StartPacketId--;
							slot.ACKsCount++;
						}
						else
						{
							newSlot = new SACKSlot(packetId, packetId);
							_slots.Insert(index, newSlot);
						}

						return;
					}
				}

				//-- New slot at the end
				newSlot = new SACKSlot(packetId, packetId);
				_slots.Add(newSlot);
			}
			finally
			{
				Interlocked.Increment(ref _acksCount);
				Monitor.Exit(this);
				CheckACKCount();
			}
		}
예제 #11
0
		internal SACKWindow()
		{
			SACKSlot slot = new SACKSlot(-1, -1);
			slot.ACKsCount = 0;
			_slots.Add(slot);
		}
예제 #12
0
		/// <summary>
		/// Used when sending a packet.
		/// </summary>
		internal void GetSLACKSlots(out SACKSlot slot1, out SACKSlot slot2, out SACKSlot slot3, out SACKSlot slot4)
		{
			slot1 = null;
			slot2 = null;
			slot3 = null;
			slot4 = null;

			lock (this)
			{
				if (_slots[0].StartPacketId < 0)
					return;

				//---- Useful when some ACKs are loosed
				slot1 = _slots[0].Clone();
				_slots[0].ACKsCount = 0;
				Interlocked.Exchange(ref _acksCount, _acksCount - slot1.ACKsCount);

				CheckACKCount();

				//---- Add all the slots
				for (int index = 1; index < _slots.Count; index++)
				{
					SACKSlot slot = _slots[index];
					if (slot.ACKsCount > 0)
					{
						Interlocked.Exchange(ref _acksCount, _acksCount - slot.ACKsCount);
						slot.ACKsCount = 0;
						
						CheckACKCount();
						
						if (slot2 == null)
							slot2 = slot.Clone();
						else if (slot3 == null)
							slot3 = slot.Clone();
						else if (slot4 == null)
						{
							slot4 = slot.Clone();
							return;
						}
					}
				}
			}
		}