public Tpm2NetSink([System.Runtime.CompilerServices.CallerMemberName] string name = "", int listenPort = 65506)
{
dataReceived = new Subject<Tpm2BlockData>();
this.cancelSource = new System.Threading.CancellationTokenSource();
Task.Run(async () =>
{
using (var udpClient = new UdpClient(listenPort))
{
var clientBuffer = new Dictionary<IPEndPoint, InternalBlockData>();
while (!this.cancelSource.IsCancellationRequested)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
InternalBlockData existingData;
clientBuffer.TryGetValue(receivedResults.RemoteEndPoint, out existingData);
if (existingData == null)
{
// New block
if (receivedResults.Buffer.Length < 5)
// Invalid
continue;
if (receivedResults.Buffer[0] != TPM2net_BlockStart)
// No start identifier
continue;
if (receivedResults.Buffer.Length < 7)
// Tpm2Net minimum size is 7 bytes (0 bytes of data, not sure if perhaps it should be minimum 8)
continue;
BlockTypes blockType;
switch (receivedResults.Buffer[1])
{
case TPM2_BlockType_Data:
blockType = BlockTypes.Data;
break;
case TPM2_BlockType_Command:
blockType = BlockTypes.Command;
break;
case TPM2_BlockType_Response:
blockType = BlockTypes.Response;
break;
default:
// Unknown
continue;
}
int blockSize = ((int)receivedResults.Buffer[2] << 8) + receivedResults.Buffer[3];
existingData = new InternalBlockData
{
Size = blockSize,
Type = blockType,
PacketNumber = receivedResults.Buffer[4],
TotalPackets = receivedResults.Buffer[5],
DataStream = new MemoryStream(blockSize)
};
int availableBytes = Math.Min(blockSize, receivedResults.Buffer.Length - 7);
existingData.DataStream.Write(receivedResults.Buffer, 6, availableBytes);
}
else
{
// Continue
int availableBytes = Math.Min(existingData.Size, receivedResults.Buffer.Length - 1);
existingData.DataStream.Write(receivedResults.Buffer, 0, availableBytes);
}
if (existingData.DataStream.Length == existingData.Size)
{
// Completed, check end of block
if (receivedResults.Buffer[receivedResults.Buffer.Length - 1] != TPM2_BlockEnd)
{
// Missing, throw away
existingData.Dispose();
if (clientBuffer.ContainsKey(receivedResults.RemoteEndPoint))
clientBuffer.Remove(receivedResults.RemoteEndPoint);
continue;
}
// All good
#if DEBUG_LOG
log.Debug("Received block of {0} bytes", existingData.DataStream.Length);
#endif
this.dataReceived.OnNext(new Tpm2BlockData(receivedResults.RemoteEndPoint, existingData));
existingData.Dispose();
}
else
{
// Not received everything yet
if (!clientBuffer.ContainsKey(receivedResults.RemoteEndPoint))
{
clientBuffer.Add(receivedResults.RemoteEndPoint, existingData);
}
}
}
foreach (InternalBlockData blockData in clientBuffer.Values)
blockData.Dispose();
clientBuffer.Clear();
}
});
Executor.Current.Register(this);
}