Example #1
0
 internal RUDPACKPacket(IPEndPoint remoteEndPoint, int packetId, RUDPPacketChannel channel, bool isConnectionAccepted)
 {
     RemoteEndPoint       = remoteEndPoint;
     Channel              = channel;
     IsConnectionAccepted = isConnectionAccepted;
     PacketId             = packetId;
 }
Example #2
0
		internal long TSReceived; // Time Stamp : when message is received

		internal RUDPIngoingPacket(RUDPSocket rudp, int packetId, byte[] payload, RUDPPacketChannel channel, long tsReceived)
		{
			RUDP = rudp;
			PacketId = packetId;
			Channel = channel;
			Payload = payload;
			TSReceived = tsReceived;
		}
Example #3
0
        internal long TSReceived;         // Time Stamp : when message is received

        internal RUDPIngoingPacket(RUDPSocket rudp, int packetId, byte[] payload, RUDPPacketChannel channel, long tsReceived)
        {
            RUDP       = rudp;
            PacketId   = packetId;
            Channel    = channel;
            Payload    = payload;
            TSReceived = tsReceived;
        }
Example #4
0
		internal RUDPOutgoingPacket(int packetId, long sequence, byte[] payload, RUDPPacketChannel channel)
		{
			PacketId = packetId;
			Sequence = sequence;
			Payload = payload;
			Channel = channel;

			Reset();
		}
Example #5
0
        internal RUDPOutgoingPacket(int packetId, long sequence, byte[] payload, RUDPPacketChannel channel)
        {
            PacketId = packetId;
            Sequence = sequence;
            Payload  = payload;
            Channel  = channel;

            Reset();
        }
Example #6
0
        static public void Deallocate(RUDPPacketChannel channel, byte[] buffer)
        {
            if (_currentAllocation < MaxAllocation)
            {
                Queue <byte[]>       queue  = _queues[(int)channel];
                ReaderWriterLockSlim rwlock = _locks[(int)channel];

                rwlock.EnterWriteLock();
                queue.Enqueue(buffer);
                rwlock.ExitWriteLock();

                _currentAllocation += buffer.Length;
            }
        }
Example #7
0
        static public byte[] Allocate(RUDPPacketChannel channel, int size)
        {
            //return new byte[size];

            Queue <byte[]>       queue  = _queues[(int)channel];
            ReaderWriterLockSlim rwlock = _locks[(int)channel];

            byte[] buffer;

            //---- Get from the cache
            rwlock.EnterWriteLock();
            if (queue.Count > 0)
            {
                buffer              = queue.Dequeue();
                _currentAllocation -= buffer.Length;

                // Only usefull when MTU change
                if (buffer.Length != size)
                {
                    Array.Resize <byte>(ref buffer, size);
                }

                rwlock.ExitWriteLock();
                return(buffer);
            }

            rwlock.ExitWriteLock();

            //---- Create new one
            if (_totalAllocation < MaxAllocation)
            {
                _totalAllocation += size;
                buffer            = new byte[size];

                // ask the garbage collector to avoid from relocating a certain object in memory
                System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned);
                GC.KeepAlive(buffer);

                return(buffer);
            }
            else
            {
                // Use the GC when we exceed the limit
                return(new byte[size]);
            }
        }
Example #8
0
		static public byte[] Allocate(RUDPPacketChannel channel, int size)
		{
			//return new byte[size];

			Queue<byte[]> queue = _queues[(int)channel];
			ReaderWriterLockSlim rwlock = _locks[(int)channel];

			byte[] buffer;

			//---- Get from the cache
			rwlock.EnterWriteLock();
			if (queue.Count > 0)
			{
				buffer = queue.Dequeue();
				_currentAllocation -= buffer.Length;

				// Only usefull when MTU change
				if (buffer.Length != size)
					Array.Resize<byte>(ref buffer, size);

				rwlock.ExitWriteLock();
				return buffer;
			}

			rwlock.ExitWriteLock();

			//---- Create new one
			if (_totalAllocation < MaxAllocation)
			{
				_totalAllocation += size;
				buffer = new byte[size];

				// ask the garbage collector to avoid from relocating a certain object in memory
				System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned);
				GC.KeepAlive(buffer);

				return buffer;
			}
			else
				// Use the GC when we exceed the limit
				return new byte[size];

		}
Example #9
0
		static public void Deallocate(RUDPPacketChannel channel, byte[] buffer)
		{
			if (_currentAllocation < MaxAllocation)
			{
				Queue<byte[]> queue = _queues[(int)channel];
				ReaderWriterLockSlim rwlock = _locks[(int)channel];

				rwlock.EnterWriteLock();
				queue.Enqueue(buffer);
				rwlock.ExitWriteLock();

				_currentAllocation += buffer.Length;
			}
		}
Example #10
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);
		}
Example #11
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;
		}
Example #12
0
		internal static bool PushPacketToSend(RUDPSocket rudp,
											bool reliablePacket,
											RUDPPacketChannel channel,
											byte[] payload,
											int offset,
											int payloadLength)
		{
			int packetId = -1;
			if (reliablePacket)
				packetId = Interlocked.Increment(ref rudp._ougoingPacketId);

			//---- Get the SACKs
			SACKSlot slot1 = null;
			SACKSlot slot2 = null;
			SACKSlot slot3 = null;
			SACKSlot slot4 = null;
			rudp._sackWindow.GetSLACKSlots(out slot1, out slot2, out slot3, out slot4);

			//---- Copy the payload to send
			byte[] rudpPayload = MakePacketPayload(rudp, packetId, channel, slot1, slot2, slot3, slot4, payload, offset, payloadLength);

			//---- Create a packet
			RUDPOutgoingPacket packet = NewOutgoingPacket(packetId, rudp._sequence, rudpPayload, channel);
			packet.CurrentCwnd = rudp._controlWindow.CWND;

			if (reliablePacket)
			{
				//---- Notify the control window
				rudp._controlWindow.OnSend(packetId, rudp._sequence, payloadLength);

				//---- Increment sequence number
				Interlocked.Exchange(ref rudp._sequence, rudp._sequence + payloadLength);
			}

			//---- In the "resend list"
			if (reliablePacket)
			{
				rudp._outgoingPacketsLock.EnterWriteLock();
				rudp._outgoingPackets.Add(packet);
				rudp._outgoingPacketsLock.ExitWriteLock();
			}

			//---- Send the packet
			packet.TSFirstSend = HiResTimer.MicroSeconds;
			if (!SocketSendPacket(rudp, packet, packet.Payload, packet.TSFirstSend))
			{
				// Nothing to do... socket is closed and reseted !
				return false;
			}

			return true;
		}
Example #13
0
		internal static RUDPOutgoingPacket NewOutgoingPacket(int packetId, long sequence, byte[] payload, RUDPPacketChannel channel)
		{
			//return new RUDPOutgoingPacket(packetId, sequence, payload, channel);
			RUDPOutgoingPacket packet;

			if (!_outgoingPacketsPools.TryDequeue(out packet))
			{
				for (int index = 0; index < 100; index++)
					_outgoingPacketsPools.Enqueue(new RUDPOutgoingPacket(-1, -1, null, RUDPPacketChannel.Undefined));
				return new RUDPOutgoingPacket(packetId, sequence, payload, channel);
			}

			packet.Reset();
			packet.PacketId = packetId;
			packet.Payload = payload;
			packet.Channel = channel;
			packet.Sequence = sequence;

			return packet;
		}
Example #14
0
		private static RUDPSocket HandlePing(PhysicalSocket physical, IPEndPoint sender, int packetId, RUDPPacketChannel channel)
		{
			RUDPSocket rudp = null;

			physical._connectedRDUPsLock.EnterReadLock();
			physical._connectedRDUPs.TryGetValue(sender, out rudp);
			physical._connectedRDUPsLock.ExitReadLock();

			//---- Ping
			if (channel == RUDPPacketChannel.Ping)
			{
				//-- This connection already exist, duplicated Ping
				if (rudp != null)
				{
					// Resend the ACK
					rudp._sackWindow.OnReceivePacket(packetId);
					return null;
				}

				//-- No accepting socket
				if (physical._acceptingRDUP == null)
				{
					// Maybe the socket is not yet ready for accepting, do nothing
					return null;
				}

				//-- Accept
				rudp = physical.OnEndAccept(sender, packetId);

				//-- ACK connection
				rudp._sackWindow.OnReceivePacket(packetId);

				//return physical._acceptingRDUP;
				return rudp;
			}

			//---- Ping , with Rendez vous
			if (rudp != null && rudp._status == RUDPSocketStatus.Connecting && rudp._isRendezVousMode)
			{
				//---- End of connection
				rudp._status = RUDPSocketStatus.Connected;
				rudp.OnEndConnect(RUDPSocketError.Success);

				//---- Accept the rendez vous connection
				rudp._sackWindow.OnReceivePacket(packetId);

				return rudp;
			}

			return null;
		}
Example #15
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);
		}