Exemple #1
0
        private async Task _sendPacketAsync(InternalPacket packet)
        {
            var stream = new BitStream();

            var hasAcks = _acks.RangeCount > 0;

            stream.WriteBit(hasAcks);

            if (hasAcks)
            {
                stream.WriteUInt((uint)_remoteSystemTime);

                stream.WriteSerializable(_acks);

                _acks.Clear();
            }

            stream.WriteBit(true);
            stream.WriteUInt((uint)(Environment.TickCount - _startTime));

            stream.WriteSerializable(packet);

            await _udp.SendAsync(stream.BaseBuffer, stream.BaseBuffer.Length, _endpoint).ConfigureAwait(false);
        }
Exemple #2
0
        public IEnumerable <byte[]> HandleDatagram(byte[] buffer)
        {
            if (buffer.Length <= 2)
            {
                yield break;
            }

            var stream = new BitStream(buffer);

            if (stream.ReadBit()) // has acks
            {
                var ourSystemTime = stream.ReadUInt();

                var roundTripTime = Environment.TickCount / 1000f - _startTime / 1000f - ourSystemTime / 1000f;

                if (_smoothedRoundTripTime.Equals(-1))
                {
                    _smoothedRoundTripTime  = roundTripTime;
                    _roundTripTimeVariation = roundTripTime / 2f;
                }
                else
                {
                    const float alpha = 0.125f;
                    const float beta  = 0.25f;

                    _roundTripTimeVariation = (long)((1 - beta) * _roundTripTimeVariation +
                                                     beta * Math.Abs(_smoothedRoundTripTime - roundTripTime));
                    _smoothedRoundTripTime = (long)((1 - alpha) * _smoothedRoundTripTime + alpha * roundTripTime);
                }

                _retransmissionTimeout = Math.Max(1, _smoothedRoundTripTime + 4 * _roundTripTimeVariation);

                var acks = new UIntRangeList();

                stream.ReadSerializable(acks);

                foreach (var ack in acks)
                {
                    if (_resends.ContainsKey(ack))
                    {
                        _resends.Remove(ack);
                    }
                }

                var actHoles = acks.GetHoles().Count(hole => _resends.ContainsKey(hole));

                if (actHoles > 0)
                {
                    _slowStartThreshold = _congestionWindow / 2;
                    _congestionWindow   = _slowStartThreshold;
                }
                else
                {
                    if (_sent >= _congestionWindow)
                    {
                        _congestionWindow += acks.Count > _slowStartThreshold && _congestionWindow > 0
                            ? acks.Count / _congestionWindow
                            : acks.Count;
                    }
                }

                _sent        = 0;
                _lastAckTime = Environment.TickCount / 1000f;
            }

            if (stream.AllRead)
            {
                yield break;
            }

            if (stream.ReadBit())
            {
                _remoteSystemTime = stream.ReadUInt();
            }

            while (!stream.AllRead)
            {
                var internalPacket = new InternalPacket();

                stream.ReadSerializable(internalPacket);

                if (internalPacket.Reliability == PacketReliability.ReliableOrdered ||
                    internalPacket.Reliability == PacketReliability.Reliable)
                {
                    _acks.Add(internalPacket.MessageNumber);
                }

                if (internalPacket.SplitPacket)
                {
                    if (!_splitPacketQueue.ContainsKey(internalPacket.SplitPacketId))
                    {
                        _splitPacketQueue[internalPacket.SplitPacketId] = new byte[internalPacket.SplitPacketCount][];
                    }

                    var splitPacket = _splitPacketQueue[internalPacket.SplitPacketId];

                    splitPacket[internalPacket.SplitPacketIndex] = internalPacket.Data;

                    if (splitPacket.All(a => a != null))
                    {
                        internalPacket.Data = splitPacket.SelectMany(b => b).ToArray();

                        _splitPacketQueue.Remove(internalPacket.SplitPacketId);

                        internalPacket.SplitPacket = false;
                    }
                    else
                    {
                        continue;
                    }
                }

                if (internalPacket.Reliability == PacketReliability.ReliableOrdered)
                {
                    if (!_lastReliabilityReceived.Contains(internalPacket.MessageNumber))
                    {
                        _lastReliabilityReceived.Add(internalPacket.MessageNumber);
                    }
                    else
                    {
                        continue;
                    }
                }

                if (internalPacket.Reliability == PacketReliability.UnreliableSequenced)
                {
                    if (internalPacket.OrderingIndex >= _sequencedReadIndex)
                    {
                        _sequencedReadIndex = (int)internalPacket.OrderingIndex + 1;
                    }
                    else
                    {
                        continue;
                    }
                }
                else if (internalPacket.Reliability == PacketReliability.ReliableOrdered)
                {
                    if (internalPacket.OrderingIndex == _orderedReadIndex)
                    {
                        _orderedReadIndex++;

                        for (var i = internalPacket.OrderingChannel + 1u; _outOfOrderPackets.ContainsKey(i); i++)
                        {
                            _orderedReadIndex++;

                            yield return(_outOfOrderPackets[i]);

                            _outOfOrderPackets.Remove(i);
                        }
                    }
                    else if (internalPacket.OrderingIndex < _orderedReadIndex)
                    {
                        continue;
                    }
                    else
                    {
                        _outOfOrderPackets[internalPacket.OrderingIndex] = internalPacket.Data;
                    }
                }

                yield return(internalPacket.Data);
            }
        }