< Summary

Information
Class: NtpServiceLibrary.NtpTime
Assembly: NtpServiceLibrary
File(s): D:\a\ntp-service\ntp-service\NtpServiceLibrary\NtpTime.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 45
Coverable lines: 45
Total lines: 114
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 12
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Buffer()100%210%
.ctor(...)0%4260%
Parse(...)0%2040%
SwapEndianness(...)100%210%
get_Size()100%210%
RetrieveNTPTime(...)0%620%

File(s)

D:\a\ntp-service\ntp-service\NtpServiceLibrary\NtpTime.cs

#LineLine coverage
 1using System.Net.Sockets;
 2using System.Net;
 3using System;
 4
 5namespace NtpServiceLibrary
 6{
 7    /// <summary>
 8    /// Provides methods for retrieving time from an NTP server.
 9    /// </summary>
 10    public class NtpTime
 11    {
 12        public const int ServerTimeout = 5000;
 13
 14        private class NtpPacket
 15        {
 16            public enum Version
 17            {
 18                Version2,
 19                Version3
 20
 21            }
 22            public enum Mode
 23            {
 24                Client,
 25                Server
 26
 27            }
 28            public const uint BufferSize = 48;
 29            public const int IntPartOffset = 40;
 30            public const int FractPartOffset = 44;
 031            public byte[] Buffer { get; }
 32
 033            public NtpPacket(Version version, Mode mode)
 034            {
 035                Buffer = new byte[BufferSize];
 036                switch (mode)
 37                {
 38                    case Mode.Client:
 039                        if (version == Version.Version3)
 040                        {
 041                            Buffer[0] = 0x1B;
 042                        }
 43                        else
 044                        {
 045                            throw new NotImplementedException();
 46                        }
 047                        break;
 48                    case Mode.Server:
 049                        throw new NotImplementedException();
 50                }
 051            }
 52
 53            public static DateTime Parse(byte[] data)
 054            {
 055                if (data == null || data.Length < BufferSize)
 056                    throw new ArgumentException("Invalid NTP response");
 57
 058                uint intPart = SwapEndianness(BitConverter.ToUInt32(data, IntPartOffset));
 059                uint fractPart = SwapEndianness(BitConverter.ToUInt32(data, FractPartOffset));
 60
 061                double milliseconds = intPart * 1000.0 + (fractPart * 1000.0 / (1UL << 32));
 062                return new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(milliseconds);
 063            }
 64
 65            private static uint SwapEndianness(uint x)
 066            {
 067                return (x >> 24) |
 068                       ((x & 0x00FF0000) >> 8) |
 069                       ((x & 0x0000FF00) << 8) |
 070                       (x << 24);
 071            }
 72
 73            public int Size
 74            {
 075                get { return Buffer.Length; }
 76            }
 77        }
 78
 79        /// <summary>
 80        /// Retrieves the current time from an NTP server over UDP.
 81        /// </summary>
 82        /// <param name="ntpServer">Hostname or IP address of the NTP server.</param>
 83        /// <param name="ntpPort">UDP port, typically 123.</param>
 84        /// <returns>UTC DateTime.</returns>
 85        public static DateTime RetrieveNTPTime(string ntpServer, int ntpPort)
 086        {
 087            if (string.IsNullOrWhiteSpace(ntpServer))
 088                throw new ArgumentNullException(nameof(ntpServer));
 89
 90            try
 091            {
 092                using (UdpClient client = new UdpClient())
 093                {
 094                    client.Client.ReceiveTimeout = ServerTimeout;
 95
 096                    client.Connect(ntpServer, ntpPort);
 97
 098                    NtpPacket packet = new NtpPacket(NtpPacket.Version.Version3, NtpPacket.Mode.Client);
 99
 0100                    client.Send(packet.Buffer, packet.Size);
 101
 0102                    IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
 103
 0104                    return NtpPacket.Parse(client.Receive(ref remoteEndPoint));
 105
 106                }
 107            }
 0108            catch (SocketException ex)
 0109            {
 0110                throw new InvalidOperationException($"Failed to contact NTP server {ntpServer}:{ntpPort}", ex);
 111            }
 0112        }
 113    }
 114}