// ********************************************************* Step 12: NTP synchronization
- // First, do a simple check whether there is a local ntp server.
- string strLocalHost = "127.0.0.1";
- int64_t nTime = NtpGetTime(strLocalHost);
-
- if (nTime < 0 || nTime != GetTime()) {
- // If not, then request current timestamp from three random NTP servers.
- uiInterface.InitMessage(_("Synchronizing time through NTP..."));
- printf("Synchronizing time through NTP...\n");
-
- for(int i = 0; i < 2; i++) {
- CNetAddr ip;
- int64_t nTime = NtpGetTime(ip);
-
- if (nTime > 0 && nTime != 2085978496) { // Skip the deliberately wrong timestamps
- AddTimeData(ip, nTime);
- printf("AddTimeData(%s, %" PRId64 ")\n", ip.ToString().c_str(), nTime);
- }
- }
+ // Trusted NTP server, it's localhost by default.
+ strTrustedUpstream = GetArg("-ntp", "localhost");
- // When done, start a periodical sampling thread
- NewThread(ThreadNtpSamples, NULL);
+ // Start periodical NTP sampling thread
+ NewThread(ThreadNtpSamples, NULL);
- uiInterface.InitMessage(_("Done"));
- printf("Done\n");
- }
// ********************************************************* Step 12: finished
uiInterface.InitMessage(_("Done loading"));
-
#ifdef WIN32
#include <winsock2.h>
#else
#endif
#include "netbase.h"
-#include "util.h"
#include "net.h"
+#include "util.h"
extern int GetRandInt(int nMax);
}
recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
-
- ntohl_fp(&msg->rec, &prt->rec);
ntohl_fp(&msg->xmt, &prt->xmt);
-
- time_t seconds_receive;
time_t seconds_transmit;
-
- Ntp2Unix(prt->rec.Ul_i.Xl_ui, seconds_receive);
Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
delete msg;
delete prt;
- return (seconds_receive + seconds_transmit) / 2;
+ return seconds_transmit;
}
int64_t NtpGetTime(CNetAddr& ip) {
return nTime;
}
-void ThreadNtpSamples(void* parg)
-{
+// NTP server, which we unconditionally trust. This may be your own installation of ntpd somewhere, for example.
+// "localhost" means "trust no one"
+std::string strTrustedUpstream = "localhost";
+
+// Current offset
+int64_t nNtpOffset = INT64_MAX;
+
+int64_t GetNtpOffset() {
+ return nNtpOffset;
+}
+
+void ThreadNtpSamples(void* parg) {
+
+ // Maximum offset is 2 hours.
+ const int64_t nMaxOffset = 7200;
+
printf("ThreadNtpSamples started\n");
vnThreadsRunning[THREAD_NTP]++;
// Make this thread recognisable as time synchronization thread
RenameThread("novacoin-ntp-samples");
- while (!fShutdown) {
- CNetAddr ip;
- int64_t nTime = NtpGetTime(ip);
+ CMedianFilter<int64_t> vTimeOffsets(200,0);
- if (nTime > 0 && nTime != 2085978496) { // Skip the deliberately wrong timestamps
- AddTimeData(ip, nTime);
+ while (!fShutdown) {
+ if (strTrustedUpstream != "localhost") {
+ // Trying to get new offset sample from trusted NTP server.
+ int64_t nClockOffset = NtpGetTime(strTrustedUpstream) - GetTime();
+
+ if (abs64(nClockOffset) < nMaxOffset) {
+ // Everything seems right, remember new trusted offset.
+ nNtpOffset = nClockOffset;
+ }
+ else {
+ // Something went wrong. Disable trusted offset sampling and wait 600 seconds.
+ nNtpOffset = INT64_MAX;
+ strTrustedUpstream = "localhost";
+
+ for (int i = 0; i < 600 && !fShutdown; i++) // Sleep for 5 minutes
+ Sleep(1000);
+
+ continue;
+ }
}
else {
- Sleep(600000); // In case of failure wait 600 seconds and then try again
- continue;
+ // Now, trying to get 2-4 samples from random NTP servers.
+ int nSamplesCount = 2 + GetRandInt(2);
+
+ for (int i = 0; i < nSamplesCount; i++) {
+ CNetAddr ip;
+ int64_t nClockOffset = NtpGetTime(ip) - GetTime();
+
+ if (abs64(nClockOffset) < nMaxOffset) { // Skip the deliberately wrong timestamps
+ vTimeOffsets.input(nClockOffset);
+ }
+ }
+
+ if (vTimeOffsets.size() > 2) {
+ nNtpOffset = vTimeOffsets.median();
+ }
+ else {
+ // Not enough offsets yet, try again 300 seconds later.
+ nNtpOffset = INT64_MAX;
+ for (int i = 0; i < 300 && !fShutdown; i++)
+ Sleep(1000);
+ continue;
+ }
}
- Sleep(43200000); // Sleep for 12 hours
+ printf("nNtpOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nNtpOffset, nNtpOffset/60);
+
+ for (int i = 0; i < 43200 && !fShutdown; i++) // Sleep for 12 hours
+ Sleep(1000);
}
vnThreadsRunning[THREAD_NTP]--;
// Get time from provided server.
int64_t NtpGetTime(std::string &strHostName);
+extern std::string strTrustedUpstream;
+
// NTP time samples thread.
void ThreadNtpSamples(void* parg);
+
+// NTP offset
+int64_t GetNtpOffset();
// - Median of other nodes clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
-static int64_t nMockTime = 0; // For unit testing
+// System clock
int64_t GetTime()
{
- if (nMockTime) return nMockTime;
-
return time(NULL);
}
-void SetMockTime(int64_t nMockTimeIn)
-{
- nMockTime = nMockTimeIn;
-}
+// Trusted NTP offset or median of NTP samples.
+extern int64_t nNtpOffset;
-static int64_t nTimeOffset = 0;
+// Median of time samples given by other nodes.
+static int64_t nNodesOffset = INT64_MAX;
+// Select time offset:
+//
+// * If NTP and system clock are in agreement within 40 minutes, then use NTP.
+// * If not, then choose between median peer time and system clock using the same condition.
int64_t GetTimeOffset()
{
- return nTimeOffset;
+ if (abs64(nNtpOffset) < 40 * 60)
+ return nNtpOffset;
+
+ if (abs64(nNodesOffset) < 40 * 60)
+ return nNodesOffset;
+
+ return 0;
}
int64_t GetAdjustedTime()
// Only let other nodes change our time by so much
if (abs64(nMedian) < 70 * 60)
{
- nTimeOffset = nMedian;
+ nNodesOffset = nMedian;
}
else
{
- nTimeOffset = 0;
+ nNodesOffset = INT64_MAX;
static bool fDone;
if (!fDone)
{
- // If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false;
+
+ // If nobody has a time different than ours but within 5 minutes of ours, give a warning
BOOST_FOREACH(int64_t nOffset, vSorted)
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
fMatch = true;
printf("%+" PRId64 " ", n);
printf("| ");
}
- printf("nTimeOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nTimeOffset, nTimeOffset/60);
+ if (nNodesOffset != INT64_MAX)
+ printf("nNodesOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nNodesOffset, nNodesOffset/60);
}
}
-
-
-
-
-
-
-
string FormatVersion(int nVersion)
{
if (nVersion%100 == 0)