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); }
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); } }