public void SendToRecvFromAsync_Datagram_UDP(IPAddress leftAddress, IPAddress rightAddress)
{
// TODO #5185: harden against packet loss
const int DatagramSize = 256;
const int DatagramsToSend = 256;
const int AckTimeout = 1000;
const int TestTimeout = 30000;
var left = new Socket(leftAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
var leftEventArgs = new SocketAsyncEventArgs();
left.BindToAnonymousPort(leftAddress);
var right = new Socket(rightAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
var rightEventArgs = new SocketAsyncEventArgs();
right.BindToAnonymousPort(rightAddress);
var leftEndpoint = (IPEndPoint)left.LocalEndPoint;
var rightEndpoint = (IPEndPoint)right.LocalEndPoint;
var receiverAck = new ManualResetEventSlim();
var senderAck = new ManualResetEventSlim();
EndPoint receiveRemote = leftEndpoint.Create(leftEndpoint.Serialize());
var receiverFinished = new TaskCompletionSource<bool>();
var receivedChecksums = new uint?[DatagramsToSend];
var receiveBuffer = new byte[DatagramSize];
int receivedDatagrams = -1;
Action<int, EndPoint> receiveHandler = null;
receiveHandler = (received, remote) =>
{
try
{
if (receivedDatagrams != -1)
{
Assert.Equal(DatagramSize, received);
Assert.Equal(rightEndpoint, remote);
int datagramId = (int)receiveBuffer[0];
Assert.Null(receivedChecksums[datagramId]);
receivedChecksums[datagramId] = Fletcher32.Checksum(receiveBuffer, 0, received);
receiverAck.Set();
Assert.True(senderAck.Wait(AckTimeout));
senderAck.Reset();
receivedDatagrams++;
if (receivedDatagrams == DatagramsToSend)
{
left.Dispose();
receiverFinished.SetResult(true);
return;
}
}
else
{
receivedDatagrams = 0;
}
left.ReceiveFromAsync(leftEventArgs, receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, receiveRemote, receiveHandler);
}
catch (Exception ex)
{
receiverFinished.SetException(ex);
}
};
receiveHandler(0, null);
var random = new Random();
var senderFinished = new TaskCompletionSource<bool>();
var sentChecksums = new uint[DatagramsToSend];
var sendBuffer = new byte[DatagramSize];
int sentDatagrams = -1;
Action<int> sendHandler = null;
sendHandler = sent =>
{
try
{
if (sentDatagrams != -1)
{
Assert.True(receiverAck.Wait(AckTimeout));
receiverAck.Reset();
senderAck.Set();
Assert.Equal(DatagramSize, sent);
sentChecksums[sentDatagrams] = Fletcher32.Checksum(sendBuffer, 0, sent);
sentDatagrams++;
if (sentDatagrams == DatagramsToSend)
{
right.Dispose();
senderFinished.SetResult(true);
return;
}
}
else
{
sentDatagrams = 0;
}
random.NextBytes(sendBuffer);
sendBuffer[0] = (byte)sentDatagrams;
right.SendToAsync(rightEventArgs, sendBuffer, 0, sendBuffer.Length, SocketFlags.None, leftEndpoint, sendHandler);
}
catch (Exception ex)
{
senderFinished.SetException(ex);
}
};
sendHandler(0);
Assert.True(receiverFinished.Task.Wait(TestTimeout));
Assert.True(senderFinished.Task.Wait(TestTimeout));
for (int i = 0; i < DatagramsToSend; i++)
{
Assert.NotNull(receivedChecksums[i]);
Assert.Equal(sentChecksums[i], (uint)receivedChecksums[i]);
}
}