|
using
System;
using
System.Net;
using
System.Net.Sockets;
/*
* NetworkTimeServer
* By Peter Slade
* Email:
pete@sladehome.com
* Web:
http://www.sladehome.com
*
* THIS CODE IS PROVIDED WITHOUT ANY
WARRANTY, AND WITHOUT ANY IMPLIED WARRANTIES
*
WITH
REGARD TO MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* USE AT YOUR OWN RISK. YOU ASSUME ALL
LIABILITIES!!!
*
*/
namespace
SladeHome.NetworkTime{
///
<summary>
///
Network Time Client
///
Provides time information from a specified
NTP server
///
</summary>
public
class
NetworkTimeClient {
private
byte []ntpData
= new
byte[48];
// Structure - per
RFC 2030
// timestamp location in NTP Structure
private
const
byte
offsetTransmitTime = 40;
private
string
server = "time-a.nist.gov";
// default server
address
private int
port = 123; //
default port
private DateTime receiveTime;
// time request
received by server
///
<summary>
/// Default
Constructor
///
</summary>
public NetworkTimeClient(){
}
///
<summary>
///
Constructor
///
</summary>
///
<param
name="host"></param>
public NetworkTimeClient(string
server) {
this.server = server;
}
///
<summary>
///
Constructor
///
</summary>
///
<param
name="server">NTP
Server</param>
///
<param name="port">Port
Number</param>
public NetworkTimeClient(string
server, int
port) {
this.server = server;
this.port = port;
}
///
<summary>
/// Connect
to the NTP server and return the date/time
///
</summary>
///
<returns></returns>
public DateTime Time{
get{
UdpClient udpSocket =
null;
try {
// resolve the IP
address of the time server
IPHostEntry address = Dns.Resolve(this.server);
IPEndPoint
endPoint =
new
IPEndPoint(address.AddressList[0],
this.port);
//
Connect to the time server
udpSocket
= new
UdpClient();
udpSocket.Connect(endPoint);
// Initialize data
structure
/*
* Per RFC 2030
* It is advisable
to fill the non-significant
* low order bits of the timestamp with a
random
* unbiased
bitstring, both to avoid systematic
* roundoff
errors and as a means of loop detection
* and
replay detection. One way of doing this is to
* generate a
random bitstring in a 64-bit word, then
* perform an arithmetic right shift a number
of bits
* equal to the
number of significant bits of the
* timestamp,
then add the result to the original
* timestamp
*/
ntpData[0] =
0x1B; // Set
version to 4, mode to client
for(int
i = 1; i < 48; i++) {
// pad with 0's
ntpData[i] = 0;
}
udpSocket.Send(ntpData,
ntpData.Length);
ntpData =
udpSocket.Receive(ref
endPoint);
receiveTime =
DateTime.Now;
//
Calc the time difference and offset for NTP
time
ulong
intpart = 0;
ulong
fractpart = 0;
for(int
i = 0; i <= 3; i++) {
intpart =
256 * intpart
+ ntpData[offsetTransmitTime + i];
}
for(int
i = 4; i<=7; i++) {
fractpart =
256 * fractpart + ntpData[offsetTransmitTime
+ i]);
}
ulong
milliseconds =
(intpart * 1000 + (fractpart * 1000) /
0x100000000L);
// Calculate the
date
/*
* NTP timestamps are represented as a
64-bit unsigned
* fixed-point
number, in seconds relative to
* 0h on 1 January 1900. The integer part is
in the
*
first
32 bits and the fraction part in the last
*
32 bits.
In the fraction part, the non-significant
*
low order can
be set to 0.
*/
TimeSpan timeSpan
=
TimeSpan.FromMilliseconds( (double)
milliseconds);
DateTime dateTime
= new
DateTime(1900, 1, 1);
dateTime +=
timeSpan;
// Calculate the
timezone offset for the user
TimeSpan
offsetAmount =
TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
DateTime
networkDateTime = (dateTime + offsetAmount);
return
networkDateTime;
}
catch(SocketException
ex) {
throw
new
Exception(ex.Message);
}
finally{
if (udpSocket
!= null){
try{
udpSocket.Close();
}
catch
(Exception){}
}
}
}
}
///
<summary>
/// Return
Network Date/Time or exception detail
///
</summary>
///
<returns></returns>
public
override
string ToString() {
try{
return
this.Time.ToString();
}
catch (Exception ex){
return
ex.ToString();
}
}
///
<summary>
/// Static
method to return the network time
///
</summary>
///
<returns>Network
Time Server Date/Time</returns>
public
static DateTime GetNetworkTime(){
NetworkTimeClient ntc =
new
NetworkTimeClient();
return ntc.Time;
}
///
<summary>
/// Static
method to return the network time
///
</summary>
///
<param
name="server">time
server address</param>
///
<returns>Network
Time Server Date/Time</returns>
public
static DateTime GetNetworkTime(string
server){
NetworkTimeClient ntc =
new
NetworkTimeClient(server);
return ntc.Time;
}
///
<summary>
/// Static
method to return the network time
///
</summary>
///
<param
name="server">time
server address</param>
///
<param name="port">time
server port</param>
///
<returns>Network
Time Server Date/Time</returns>
public
static DateTime GetNetworkTime(string
server, int
port){
NetworkTimeClient ntc =
new
NetworkTimeClient(server, port);
return ntc.Time;
}
} // class
} //
namespace
|