Пример #1
0
        /// <summary>
        /// Reads a packet from a stream with the given size in bytes or returns null if the packet cannot be parsed.
        /// </summary>
        public static Packet Read(InStream Stream, int Size)
        {
            Packet packet = new Packet();

            // Read flags and header
            if ((Size -= StreamSize.Byte + StreamSize.Int) < 0)
                return null;
            PacketFlags flags = (PacketFlags)Stream.ReadByte();
            packet.SequenceNumber = Stream.ReadInt();
            packet.PingRequest = (flags & PacketFlags.PingRequest) == PacketFlags.PingRequest;
            packet.PingResponse = (flags & PacketFlags.PingResponse) == PacketFlags.PingResponse;

            // Read additional information
            if ((flags & PacketFlags.Acknowledgement) == PacketFlags.Acknowledgement)
            {
                if ((Size -= StreamSize.Int) < 0)
                    return null;
                packet.AcknowledgementNumber = Stream.ReadInt();
            }
            if ((flags & PacketFlags.RoundTripTime) == PacketFlags.RoundTripTime)
            {
                if ((Size -= StreamSize.Double) < 0)
                    return null;
                packet.RoundTripTime = Stream.ReadDouble();
            }

            // Read chunk if any
            if ((flags & PacketFlags.Chunk) == PacketFlags.Chunk)
            {
                packet.ChunkInitial = (flags & PacketFlags.ChunkInitial) == PacketFlags.ChunkInitial;
                packet.ChunkFinal = (flags & PacketFlags.ChunkFinal) == PacketFlags.ChunkFinal;

                byte[] data = new byte[Size];
                Stream.Read(data, 0, data.Length);
                packet.ChunkData = data;

                return packet;
            }
            else
            {
                // A packet can only be a disconnect if it does not have a chunk
                packet.Disconnect = (flags & PacketFlags.Disconnect) == PacketFlags.Disconnect;

                // Make sure this is the end of the packet
                if (Size == 0)
                    return packet;
                else
                    return null;
            }
        }
Пример #2
0
        /// <summary>
        /// Writes a packet to a stream.
        /// </summary>
        public static void Write(Packet Packet, OutStream Stream)
        {
            // Build flags and header
            PacketFlags flags = PacketFlags.Empty;
            if (Packet.AcknowledgementNumber.HasValue)
                flags |= PacketFlags.Acknowledgement;
            if (Packet.RoundTripTime.HasValue)
                flags |= PacketFlags.RoundTripTime;
            if (Packet.ChunkData != null)
            {
                flags |= PacketFlags.Chunk;
                if (Packet.ChunkInitial)
                    flags |= PacketFlags.ChunkInitial;
                if (Packet.ChunkFinal)
                    flags |= PacketFlags.ChunkFinal;
            }
            if (Packet.PingRequest)
                flags |= PacketFlags.PingRequest;
            if (Packet.PingResponse)
                flags |= PacketFlags.PingResponse;
            if (Packet.Disconnect)
                flags |= PacketFlags.Disconnect;
            Stream.WriteByte((byte)flags);
            Stream.WriteInt(Packet.SequenceNumber);

            // Additional information
            int ack;
            if (Packet.AcknowledgementNumber.TryGetValue(out ack))
                Stream.WriteInt(ack);

            double rtt;
            if (Packet.RoundTripTime.TryGetValue(out rtt))
                Stream.WriteDouble(rtt);

            // Chunk
            if (Packet.ChunkData != null)
                Stream.Write(Packet.ChunkData, 0, Packet.ChunkData.Length);
        }
Пример #3
0
 /// <summary>
 /// Immediately sends a ping response packet of some sort.
 /// </summary>
 private void _SendPingResponse(UDPHub Hub)
 {
     byte[] data = null;
     bool initial = false;
     bool final = false;
     int sequencenumber = 0;
     Packet packet;
     if(this._OutTerminal.Process(ref sequencenumber, ref data, ref initial, ref final))
     {
         packet = new Packet
         {
             SequenceNumber = sequencenumber,
             ChunkData = data,
             ChunkInitial = initial,
             ChunkFinal = final
         };
     }
     else
     {
         packet = new Packet
         {
             SequenceNumber = this._OutTerminal.SendNumber
         };
     }
     packet.PingResponse = true;
     Hub.Send(packet, this.EndPoint);
 }
Пример #4
0
        /// <summary>
        /// Fills the given packet with additional information.
        /// </summary>
        private void _FillAdditional(Packet Packet)
        {
            if (this._ShouldSendAcknowledgement)
            {
                this._ShouldSendAcknowledgement = false;
                Packet.AcknowledgementNumber = this.InTerminal.AcknowledgementNumber;
            }

            if (this._ShouldSendRoundTripTime)
            {
                this._ShouldSendRoundTripTime = false;
                Packet.RoundTripTime = this.RoundTripTime;
            }
        }
Пример #5
0
        /// <summary>
        /// Updates the state of the peer and sends packets if needed.
        /// </summary>
        internal void _Update(UDPHub Hub, double Time, out bool Remove)
        {
            UDPHubSettings settings = this._Settings;
            OutTerminal oterm = this._OutTerminal;

            // Handle waves
            this._WaveDelay -= Time;
            if (this._WaveDelay <= 0.0)
            {
                // Check acknowledgement and adjust wave size
                if (oterm.AcknowledgementNumber == oterm.SendNumber)
                {
                    if (this._FullWave)
                    {
                        this._WaveSize++;
                        this._FullWave = false;
                    }
                }
                else
                {
                    oterm.SendNumber = oterm.AcknowledgementNumber;
                    if (this._WaveSize > 1)
                    {
                        this._WaveSize--;
                    }
                }

                int chunksequencenumber = 0;
                byte[] chunkdata = null;
                bool chunkinitial = false;
                bool chunkfinal = false;
                int wavesize = 0;
                if (oterm.Process(ref chunksequencenumber, ref chunkdata, ref chunkinitial, ref chunkfinal))
                {
                    while (true)
                    {
                        // Send chunk
                        wavesize++;
                        Packet chunk = new Packet
                        {
                            SequenceNumber = chunksequencenumber,
                            ChunkData = chunkdata,
                            ChunkInitial = chunkinitial,
                            ChunkFinal = chunkfinal
                        };
                        this._FillAdditional(chunk);
                        Hub.Send(chunk, this._EndPoint);

                        // Check if wave is full
                        if (wavesize == this._WaveSize)
                        {
                            this._FullWave = true;
                            break;
                        }

                        // Get next chunk
                        if (!oterm.Process(ref chunksequencenumber, ref chunkdata, ref chunkinitial, ref chunkfinal))
                        {
                            break;
                        }
                    }

                    // Reset delays
                    this._WaveDelay = this._RoundTripTime + settings.WaveRate;
                    this._KeepAliveDelay = settings.KeepAliveDelay;
                }
            }

            // Send keep alive if needed
            this._KeepAliveDelay -= Time;
            if (this._KeepAliveDelay <= 0.0)
            {
                Packet packet = new Packet
                {
                    SequenceNumber = this._OutTerminal.SendNumber
                };
                this._FillAdditional(packet);
                Hub.Send(packet, this.EndPoint);
                this._KeepAliveDelay = settings.KeepAliveDelay;
            }

            // Check for implicit disconnect
            Remove = false;
            this._ExpireDelay -= Time;
            if (this._ExpireDelay <= 0.0)
            {
                Remove = true;
            }
        }
Пример #6
0
        /// <summary>
        /// Called when an (unvalidated) packet is received for this peer.
        /// </summary>
        internal void _Receive(UDPHubSettings Settings, UDPHub Hub, Packet Packet, out bool Remove)
        {
            Remove = false;

            // Validate
            if (!this._Valid(Packet.SequenceNumber))
                return;

            // Disconnect?
            if (Packet.Disconnect)
            {
                Remove = true;
                return;
            }

            // Reset expire delay
            this._ExpireDelay = Settings.ExpireDelay;

            // Read additional information
            int ack;
            if (Packet.AcknowledgementNumber.TryGetValue(out ack))
            {
                this._OutTerminal.AcknowledgementNumber = ack;
            }
            double rtt;
            if (Packet.RoundTripTime.TryGetValue(out rtt))
            {
                this._RoundTripTime = rtt;
            }

            // Chunk?
            if (Packet.ChunkData != null)
            {
                this._Process(Packet.SequenceNumber, Packet.ChunkData, Packet.ChunkInitial, Packet.ChunkFinal);
            }

            // Ping?
            if (Packet.PingRequest)
            {
                this._SendPingResponse(Hub);
            }
        }
Пример #7
0
 /// <summary>
 /// Uses the connection and settings of this hub to send a packet to the given endpoint.
 /// </summary>
 public void Send(Packet Packet, IPEndPoint To)
 {
     BufferOutStream bos = new BufferOutStream(this._Settings.SendBuffer, 0);
     Packet.Write(Packet, bos);
     this._UDP.Send(To, Data.FromBuffer(bos.Buffer, 0, bos.Position));
 }