void OnNTPTimeReceived(Windows.Networking.Sockets.DatagramSocket socket, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs eventArguments)
{
int currentRTT = (int)ntpResponseMonitor.ElapsedMilliseconds;
Debug.WriteLine($"NtpSync: current RTT {currentRTT}");
ntpResponseMonitor.Stop();
if (currentNtpQueryCount < MaxNtpRTTProbeQuery)
{
//we only trace 'min' RTT within the RTT probe attempts
if (minNtpRTT == -1 || minNtpRTT > currentRTT)
{
minNtpRTT = currentRTT;
if (minNtpRTT == 0)
minNtpRTT = 1; //in case we got response so fast, consider it to be 1ms.
}
averageNtpRTT = (averageNtpRTT * (currentNtpQueryCount - 1) + currentRTT) / currentNtpQueryCount;
if (averageNtpRTT < 1)
{
averageNtpRTT = 1;
}
RunOnUiThread(() =>
{
ntpQueryTimer.Stop();
ntpRTTIntervalTimer.Start();
});
return;
}
//if currentRTT is good enough, e.g.: closer to minRTT, then, we don't have to continue to query.
if (currentRTT > (averageNtpRTT + minNtpRTT) / 2)
{
RunOnUiThread(() =>
{
ntpQueryTimer.Stop();
ntpRTTIntervalTimer.Start();
});
return;
}
byte[] ntpData = new byte[48];
eventArguments.GetDataReader().ReadBytes(ntpData);
//Offset to get to the "Transmit Timestamp" field (time at which the reply
//departed the server for the client, in 64-bit timestamp format."
const byte serverReplyTime = 40;
//Get the seconds part
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
//Get the seconds fraction
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
ulong milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
RunOnUiThread(() =>
{
OnNTPTimeAvailable?.Invoke((long)milliseconds + currentRTT / 2);
});
socket.Dispose();
ReportNtpSyncStatus(true, currentRTT);
}