-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimewrap.pas
178 lines (150 loc) · 4.88 KB
/
timewrap.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
{ ************************************************************************
NetTime is copyrighted by Graham Mainwaring. Permission is hereby
granted to use, modify, redistribute and create derivative works
provided this attribution is not removed. I also request that if you
make any useful changes, please e-mail the diffs to [email protected]
so that I can include them in an 'official' release.
************************************************************************ }
unit timewrap;
interface
uses Windows, Classes, SysUtils, NetTimeCommon, WinSockUtil;
procedure GetTimeFromServer(const h: string; const protocol: TTimeProto;
const Port: integer; var status: TSyncServerStatus; var Time: TDateTime;
var NetLag: TDateTime);
procedure GetTimeFromServerAsync(const h: string; const protocol: TTimeProto;
const Port: integer; var status: TSyncServerStatus; var Time: TDateTime;
var NetLag: TDateTime; var Done: boolean);
procedure FigureBestKnownTime(const ServerCount: integer;
const Servers: TServerDefArray; var Status: TSyncStatus; var Time: TDateTime);
implementation
uses unixtime, ntptime;
procedure GetTimeFromServer(const h: string; const protocol: TTimeProto;
const Port: integer; var Status: TSyncServerStatus; var Time: TDateTime;
var NetLag: TDateTime);
begin
case protocol of
ttpRFC868_UDP: GetTimeFromHost(h,port,true,status,time,netlag);
ttpRFC868_TCP: GetTimeFromHost(h,port,false,status,time,netlag);
ttpNTP: GetTimeFromNTP(h,port,status,time,netlag);
else
status := ssUnconfigured;
end;
end;
type
PBoolean = ^boolean;
PStatus = ^TSyncServerStatus;
PDateTime = ^TDateTime;
TRetrieverThread = class(TThread)
protected
FHost: string;
FProtocol: TTimeProto;
FPort: integer;
FStatusPtr: PStatus;
FTimePtr: PDateTime;
FNetLagPtr: PDateTime;
FDonePtr: PBoolean;
procedure Execute; override;
public
constructor Create(const h: string; const protocol: TTimeProto;
const Port: integer; const StatusPtr: PStatus; const TimePtr: PDateTime;
const NetLagPtr: PDateTime; const DonePtr: PBoolean);
end;
constructor TRetrieverThread.Create(const h: string; const protocol: TTimeProto;
const Port: integer; const StatusPtr: PStatus; const TimePtr: PDateTime;
const NetLagPtr: PDateTime; const DonePtr: PBoolean);
begin
inherited Create(true);
FreeOnTerminate := true;
FHost := h;
FProtocol := protocol;
FPort := Port;
FStatusPtr := StatusPtr;
FTimePtr := TimePtr;
FNetLagPtr := NetLagPtr;
FDonePtr := DonePtr;
DonePtr^ := false;
Resume;
end;
procedure TRetrieverThread.Execute;
var
SStatus: TSyncServerStatus;
STime, SNetLag: TDateTime;
begin
try
try
GetTimeFromServer(FHost, FProtocol, FPort, SStatus, STime, SNetLag);
FStatusPtr^ := SStatus;
FTimePtr^ := STime;
FNetLagPtr^ := SNetLag;
except
FStatusPtr^ := ssFailed;
end;
finally
FDonePtr^ := true;
end;
end;
procedure GetTimeFromServerAsync(const h: string; const protocol: TTimeProto;
const Port: integer; var Status: TSyncServerStatus; var Time: TDateTime;
var NetLag: TDateTime; var Done: boolean);
begin
TRetrieverThread.Create(h,protocol,port,@status,@time,@netlag,@done);
end;
procedure FigureBestKnownTime(const ServerCount: integer;
const Servers: TServerDefArray; var Status: TSyncStatus; var Time: TDateTime);
var
i: integer;
GotCount: integer;
ThrdData, CalcData: array[0..MaxServers-1] of TServerData;
AllDone: boolean;
begin
for i := ServerCount to MaxServers-1 do
Status.ss[i] := ssUnconfigured;
if not HaveLocalAddress then
begin
Status.Synchronized := false;
for i := 0 to ServerCount-1 do
Status.ss[i] := ssFailed;
Time := Now;
exit;
end;
// Retrieve all server times
for i := 0 to ServerCount-1 do
begin
ThrdData[i].RetrievalTime := 0;
Status.ss[i] := ssFailed;
end;
for i := 0 to ServerCount-1 do
GetTimeFromServerAsync(Servers[i].Hostname, Servers[i].Protocol,
Servers[i].Port, Status.ss[i], ThrdData[i].Time, ThrdData[i].NetLag,
ThrdData[i].Done);
repeat
Sleep(GUISleepTime);
AllDone := true;
for i := 0 to ServerCount-1 do
if not ThrdData[i].Done then
AllDone := false
else if ThrdData[i].RetrievalTime = 0 then
ThrdData[i].RetrievalTime := Now;
until AllDone;
// Extract only those times that were good
GotCount := 0;
for i := 0 to ServerCount-1 do
if (Status.ss[i] = ssGood) then
begin
CalcData[GotCount] := ThrdData[i];
inc(GotCount);
end;
// If no good times, overall result is false
if GotCount = 0 then
begin
Status.Synchronized := false;
exit;
end
else
Status.Synchronized := true;
//TODO: find a better strategy here.
NormalizeTimes(@CalcData,GotCount);
SortServerData(@CalcData,GotCount,sdsByTime,true);
Time := CalcData[GotCount div 2].Time;
end;
end.