public async Task <Packets.RegularPacket> CutNextPacketAsync()
{
if (!this._connectionid.HasValue)
{
throw new InvalidOperationException("Connection ID is not established!");
}
if (this.Count == 0)
{
return(null);
}
uint remaining = Packets.AbstractPacketBase.MTU;
ulong packetNumber;
lock (this._packetNumberLock)
{
this._packetNumber++;
packetNumber = this._packetNumber;
}
var regular = new Packets.RegularPacket(this._connectionid.Value, packetNumber, null); // TODO: FEC GROUP's.
remaining -= regular.GetHeaderLength();
MultiplexedTransfer nextTransfer;
long assignedDataSize;
bool fin;
StreamFrame streamFrame;
lock (this._dequeueLock)
{
MultiplexedTransfer peekedTransfer;
do
{
if (!this.TryPeek(out peekedTransfer))
{
return(null); // My queue is _now_ empty, just say nothing to do.
}
// Prototype our stream frame
var streamRemainingByteCount = peekedTransfer.Stream.Length - peekedTransfer.Stream.Position;
streamFrame = new StreamFrame(peekedTransfer.StreamId, Convert.ToUInt64(peekedTransfer.Stream.Position));
var prototypeLength = streamFrame.GetMetadataLength();
assignedDataSize = Math.Min(remaining, prototypeLength);
var transferDone = assignedDataSize == streamRemainingByteCount;
fin = transferDone && peekedTransfer.TerminateStream;
if (!this.TryDequeue(out nextTransfer))
{
return(null); // My queue is _now_ empty, just say nothing to do.
}
if (nextTransfer.TransferId != peekedTransfer.TransferId)
{
this.Enqueue(nextTransfer); // Whoops, something changed outside of our lock... so, redo our calculations.
}
}while (nextTransfer.TransferId != peekedTransfer.TransferId);
}
try
{
// Hydrate our stream frame prototype
var streamData = new byte[assignedDataSize];
await nextTransfer.Stream.ReadAsync(streamData, (int)nextTransfer.Stream.Position, streamData.Length);
streamFrame.SetData(streamData, fin);
}
catch (Exception)
{
// Something went wrong. Requeue the transfer.
this.Enqueue(nextTransfer);
throw;
}
return(regular);
}