public async Task <NtpMessage> SendAsync() { var timeServerEndPoint = GetIPEndPoint(this.Server, NtpPort); NtpMessage responsePacket; Timestamp transmitTimestamp; using (var updClient = new UdpClient(this.Port)) { updClient.Connect(timeServerEndPoint); transmitTimestamp = new Timestamp(DateTime.UtcNow); var ntpPacket = new NtpMessage(NtpVersion, Mode.Client, transmitTimestamp); var ntpRequestPayload = ntpPacket.GetBytes(); await updClient.SendAsync(ntpRequestPayload, ntpRequestPayload.Length); // TODO Add timeout var response = await updClient.ReceiveAsync(); responsePacket = new NtpMessage(response.Buffer, DateTime.UtcNow); } // Validate the response if (!ResponseIsValid(responsePacket, transmitTimestamp)) { throw new InvalidOperationException("The response was not valid."); } return(responsePacket); }
private static bool ResponseIsValid(NtpMessage response, Timestamp transmitTimestamp) { if (response.Stratum == Stratum.Unspecified) { return(false); } if (response.OriginateTimestamp.Seconds != transmitTimestamp.Seconds) { return(false); } /* * https://tools.ietf.org/html/rfc4330 * "4. The server reply should be discarded if any of the LI, Stratum, * or Transmit Timestamp fields is 0 or the Mode field is not 4 * (unicast) or 5 (broadcast)." * * LI should not be 3? */ //if (response.LeapIndicator == LeapIndicator.NoWarning) //{ // return false; //} if (response.Mode != Mode.Server) { return(false); } if (response.TransmitTimestamp.Seconds == 0) { return(false); } if (response.RootDelay.Seconds >= 1) { return(false); } if (response.RootDispersion.Seconds >= 1) { return(false); } return(true); }