I’m writing an application in C# that needs to know if the system time is not fake (only if the network is on). For this reason, I make a class that retrieves the time from a NTP server. The class is written to prevent that the same servers are called too often using a simple circular array. For the data returned by the servers, I invite you to see the RFC-2030 .
using System ;
using System. IO ;
using System. Runtime. Serialization ;
using System. Net ;
using System. Net. Sockets ;
public class NoServerFoundException : System. Exception {
public NoServerFoundException ( ) : base ( ) { }
public NoServerFoundException ( string message) : base ( message) { }
public NoServerFoundException ( string message,
System. Exception inner) : base ( message, inner) { }
protected NoServerFoundException ( SerializationInfo info,
System. Runtime. Serialization. StreamingContext context) { }
}
class NetworkTime {
private const int requestTimeout = 3000 ;
private const int timesForEachServer = 5 ;
private const byte offTime = 40 ;
private uint lastSrv;
public static string [ ] srvs = {
"time.nist.gov" ,
"pool.ntp.org" ,
"europe.pool.ntp.org" ,
"asia.pool.ntp.org" ,
"oceania.pool.ntp.org" ,
"north-america.pool.ntp.org" ,
"south-america.pool.ntp.org" ,
"africa.pool.ntp.org" ,
"ntp1.inrim.it" ,
"ntp2.inrim.it"
} ;
public NetworkTime ( ) {
Random rnd = new Random ( DateTime. Now. Millisecond) ;
lastSrv = ( uint ) rnd. Next ( 0 , srvs. Length) ;
}
private IPAddress getServer ( ) {
lastSrv = ( uint ) ( ( lastSrv + 1 ) % srvs. Length) ;
IPAddress[ ] address = Dns. GetHostEntry ( srvs[ lastSrv] ) . AddressList;
if ( address == null || address. Length == 0 )
throw new NoServerFoundException ( "no ip found" ) ;
return address[ 0 ] ;
}
public DateTime GetDateTime ( ) { return GetDateTime ( false ) ; }
public DateTime GetDateTime ( bool utc) {
for ( int st = 0 ; st < srvs. Length * timesForEachServer; st++ ) {
try {
IPAddress ip = getServer ( ) ;
IPEndPoint ipEndP = new IPEndPoint ( ip, 123 ) ;
Socket sk = new Socket ( AddressFamily. InterNetwork,
SocketType. Dgram,
ProtocolType. Udp) ;
sk. ReceiveTimeout = requestTimeout;
sk. Connect ( ipEndP) ;
byte [ ] data = new byte [ 48 ] ;
data[ 0 ] = 0x23 ;
for ( int i = 1 ; i < 48 ; i++ ) data[ i] = 0 ;
sk. Send ( data) ;
sk. Receive ( data) ;
byte [ ] integerPart = new byte [ 4 ] ;
integerPart[ 0 ] = data[ offTime + 3 ] ;
integerPart[ 1 ] = data[ offTime + 2 ] ;
integerPart[ 2 ] = data[ offTime + 1 ] ;
integerPart[ 3 ] = data[ offTime + 0 ] ;
byte [ ] fractPart = new byte [ 4 ] ;
fractPart[ 0 ] = data[ offTime + 7 ] ;
fractPart[ 1 ] = data[ offTime + 6 ] ;
fractPart[ 2 ] = data[ offTime + 5 ] ;
fractPart[ 3 ] = data[ offTime + 4 ] ;
long ms = ( long ) (
( ulong ) BitConverter. ToUInt32 ( integerPart, 0 ) * 1000
+ ( ( ulong ) BitConverter. ToUInt32 ( fractPart, 0 ) * 1000 )
/ 0x100000000L ) ;
sk. Close ( ) ;
DateTime date = new DateTime ( 1900 , 1 , 1 ) ;
date += TimeSpan. FromTicks ( ms * TimeSpan. TicksPerMillisecond) ;
return utc ? date : date. ToLocalTime ( ) ;
} catch ( Exception ex) { }
}
throw new NoServerFoundException ( "no working server has been found" ) ;
}
}