📄 sntp.cxx
字号:
} else {
iErr = ERROR_SUCCESS;
fSystemTimeCorrect = TRUE;
}
DWORD dw;
DWORD dwType = 0;
DWORD dwSize = sizeof(dw);
if ((iErr == ERROR_SUCCESS) && (ERROR_SUCCESS == RegQueryValueEx (hk, L"ServerRole", NULL, &dwType, (LPBYTE)&dw, &dwSize)) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dw)) && dw)
fHaveServer = TRUE;
dwType = 0;
dwSize = sizeof(dw);
if ((ERROR_SUCCESS == RegQueryValueEx (hk, L"trustlocalclock", NULL, &dwType, (LPBYTE)&dw, &dwSize)) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dw)) && dw)
fSystemTimeCorrect = TRUE;
if (fHaveServer) {
iErr = GetAddressList (hk, L"multicast", (char *)sntp_mcasts, SVSUTIL_ARRLEN(sntp_mcasts), SVSUTIL_ARRLEN(sntp_mcasts[0]), &cMcasts);
if ((iErr == ERROR_SUCCESS) && cMcasts) {
if ((ERROR_SUCCESS == RegQueryValueEx (hk, L"multicastperiod", NULL, &dwType, (LPBYTE)&dw, &dwSize)) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dw)) && (dw > MIN_MULTICAST))
dwMulticastPeriodMS = dw;
else {
iErr = ERROR_BAD_CONFIGURATION;
RETAILMSG(1, (L"[TIMESVC] Configuration error: Multicast period required. Aborting.\r\n"));
}
}
}
RegCloseKey (hk);
} else {
fHaveClient = TRUE;
fHaveServer = TRUE;
iErr = ERROR_SUCCESS;
strcpy ((char *)sntp_servers[0], "time.windows.com");
cServers = 1;
sntp_mcasts[0][0] = '\0';
cMcasts = 0; // No multicasts
dwRefreshMS = 14*24*60*60*1000; // Synchronize clock every two weeks
dwRecoveryRefreshMS = 30*60*1000; // Try every half hour if it fails
dwAdjustThreshMS = 24*60*60*1000; // Allow one day
fSystemTimeCorrect = TRUE; // Server provides time even if time synch failed
}
if (fHaveServer) {
}
for (int i = 0 ; i < cServers ; ++i) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: sntp server : %a\r\n", sntp_servers[i]));
}
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: client : %s\r\n", fHaveClient ? L"enabled" : L"disabled"));
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: server : %s\r\n", fHaveServer ? L"enabled" : L"disabled"));
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: regular refresh : %d ms (%d day(s))\r\n", dwRefreshMS, dwRefreshMS/(24*60*60*1000)));
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: accelerated refresh : %d ms (%d day(s))\r\n", dwRecoveryRefreshMS, dwRecoveryRefreshMS/(24*60*60*1000)));
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: adjustment threshold : %d ms\r\n", dwAdjustThreshMS));
if (fHaveServer) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: system clock : %s\r\n", fSystemTimeCorrect ? L"presumed correct" : L"presumed wrong if not updates"));
for (int i = 0 ; i < cMcasts ; ++i) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: multicast address : %a\r\n", sntp_mcasts[i]));
}
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Configuration: multicast period : %d ms\r\n", dwMulticastPeriodMS));
}
return iErr;
}
int TimeState::ForcedUpdate (void) {
fRefreshRequired = TRUE;
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Client: updating time NOW\r\n"));
if (ckNextRefresh)
pEvents->UnScheduleEvent (ckNextRefresh);
if (! fSystemTimeCorrect)
fForceTimeToServer = TRUE;
if (! (ckNextRefresh = pEvents->ScheduleEvent (TimeRefreshThread, NULL, 0)))
return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
}
int TimeState::UpdateNowOrLater (enum When when, int fForceTime) {
if (! fHaveClient) {
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Client: not enabled; update request ignored\r\n"));
return ERROR_SUCCESS;
}
DWORD dwTimeout;
if (when == Now) {
fRefreshRequired = TRUE;
dwTimeout = NULL;
} else if (when == Shortly) {
SVSUTIL_ASSERT (fRefreshRequired);
dwTimeout = dwRecoveryRefreshMS;
} else
dwTimeout = dwRefreshMS;
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Client: schedule time update in %d ms %s\r\n", dwTimeout, fForceTime ? L"(require refresh)" : L""));
if (ckNextRefresh)
pEvents->UnScheduleEvent (ckNextRefresh);
if (fForceTime || (! fSystemTimeCorrect))
fForceTimeToServer = TRUE;
if (! (ckNextRefresh = pEvents->ScheduleEvent (TimeRefreshThread, NULL, dwTimeout)))
return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
}
int TimeState::TimeChanged (void) {
DEBUGMSG(ZONE_TRACE, (L"[TIMESVC] Server: Time changed - multicast now?\r\n"));
if (cMcasts == 0)
return 0;
if (ckNextMulticast)
pEvents->UnScheduleEvent (ckNextMulticast);
if (! (ckNextMulticast = pEvents->ScheduleEvent (MulticastThread, NULL, 0)))
return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
}
int TimeState::Start (void) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Service starting\r\n"));
pEvents = new SVSThreadPool (5);
if (! pEvents) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Start error: Out of memory allocating threads\r\n"));
return ERROR_OUTOFMEMORY;
}
if (fHaveServer) {
ADDRINFO aiHints;
ADDRINFO *paiLocal = NULL;
memset(&aiHints, 0, sizeof(aiHints));
aiHints.ai_family = PF_UNSPEC;
aiHints.ai_socktype = SOCK_DGRAM;
aiHints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
iSock = 0;
int iErr = ERROR_SUCCESS;
if (0 != getaddrinfo(NULL, NTP_PORT_A, &aiHints, &paiLocal)) {
iErr = GetLastError ();
DEBUGMSG(ZONE_ERROR,(L"[TIMESVC] Start error: getaddrinfo() fails, GLE=0x%08x\r\n",iErr));
} else {
for (ADDRINFO *paiTrav = paiLocal; paiTrav && (iSock < SVSUTIL_ARRLEN(saServer)) ; paiTrav = paiTrav->ai_next) {
if (INVALID_SOCKET == (saServer[iSock] = socket(paiTrav->ai_family, paiTrav->ai_socktype, paiTrav->ai_protocol)))
continue;
if (SOCKET_ERROR == bind(saServer[iSock], paiTrav->ai_addr, paiTrav->ai_addrlen)) {
iErr = GetLastError ();
DEBUGMSG(ZONE_ERROR,(L"[TIMESVC] Start error: failed to bind socket, GLE=0x%08x\r\n",iErr));
closesocket (saServer[iSock]);
continue;
}
++iSock;
}
}
if (paiLocal)
freeaddrinfo(paiLocal);
if (iSock == 0) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Start error: failure to register time server (error %d)\r\n", iErr));
delete pEvents;
ReInit ();
return iErr;
}
if ( ! pEvents->ScheduleEvent (RxThread, NULL)) {
for (int i = 0 ; i < iSock ; ++i)
closesocket (saServer[i]);
SVSThreadPool *pp = pEvents;
ReInit ();
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Start error: Out of memory scheduling server thread\r\n"));
Unlock ();
delete pp;
Lock ();
return ERROR_OUTOFMEMORY;
}
}
if (ERROR_SUCCESS != UpdateNowOrLater (Now)) {
for (int i = 0 ; i < iSock ; ++i)
closesocket (saServer[i]);
SVSThreadPool *pp = pEvents;
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Start error: Out of memory scheduling time update\r\n"));
ReInit ();
Unlock ();
delete pp;
Lock ();
return ERROR_OUTOFMEMORY;
}
fStarted = TRUE;
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Service started successfully\r\n"));
return ERROR_SUCCESS;
}
SVSThreadPool *TimeState::Stop (void) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Stopping service\r\n"));
fStarted = FALSE;
for (int i = 0 ; i < iSock ; ++i) {
closesocket (saServer[i]);
saServer[i] = INVALID_SOCKET;
}
iSock = 0;
SVSThreadPool *pp = pEvents;
pEvents = NULL;
return pp;
}
///////////////////////////////////////////////////////////////////////
//
// Globals
//
//
static TimeState *gpTS = NULL;
///////////////////////////////////////////////////////////////////////
//
// Service functions
//
// Note: NTP time conversion functions derived from XP's NTP sources (ntpbase.*)
//
static inline unsigned char EndianSwap (unsigned char x) {
return x;
}
static inline unsigned short EndianSwap (unsigned short x) {
return (EndianSwap ((unsigned char)x) << 8) | EndianSwap ((unsigned char)(x >> 8));
}
static inline unsigned int EndianSwap (unsigned int x) {
return (EndianSwap ((unsigned short)x) << 16) | EndianSwap ((unsigned short)(x >> 16));
}
static inline unsigned __int64 EndianSwap (unsigned __int64 x) {
return (((unsigned __int64)EndianSwap ((unsigned int)x)) << 32) | EndianSwap ((unsigned int)(x >> 32));
}
static unsigned __int64 NtTimeEpochFromNtpTimeEpoch(unsigned __int64 te) {
//return (qwNtpTime*(10**7)/(2**32))+NTPTIMEOFFSET
// ==>
//return (qwNtpTime*( 5**7)/(2**25))+NTPTIMEOFFSET
// ==>
//return ((qwNTPtime*FIVETOTHESEVETH)>>25)+NTPTIMEOFFSET;
// ==>
// Note: 'After' division, we round (instead of truncate) the result for better precision
unsigned __int64 qwNtpTime=EndianSwap(te);
unsigned __int64 qwTemp=((qwNtpTime&0x00000000FFFFFFFF)*FIVETOTHESEVETH)+0x0000000001000000; //rounding step: if 25th bit is set, round up;
return (qwTemp>>25) + ((qwNtpTime&0xFFFFFFFF00000000)>>25)*FIVETOTHESEVETH + NTPTIMEOFFSET;
}
static unsigned __int64 NtpTimeEpochFromNtTimeEpoch(unsigned __int64 te) {
//return (qwNtTime-NTPTIMEOFFSET)*(2**32)/(10**7);
// ==>
//return (qwNtTime-NTPTIMEOFFSET)*(2**25)/(5**7);
// ==>
//return ((qwNtTime-NTPTIMEOFFSET)<<25)/FIVETOTHESEVETH);
// ==>
// Note: The high bit is lost (and assumed to be zero) but
// it will not be set for another 29,000 years (around year 31587). No big loss.
// Note: 'After' division, we truncate the result because the precision of NTP already excessive
unsigned __int64 qwTemp=(te-NTPTIMEOFFSET)<<1;
unsigned __int64 qwHigh=qwTemp>>8;
unsigned __int64 qwLow=(qwHigh%FIVETOTHESEVETH)<<32 | (qwTemp&0x00000000000000FF)<<24;
return EndianSwap(((qwHigh/FIVETOTHESEVETH)<<32) | (qwLow/FIVETOTHESEVETH));
}
static void GetCurrTimeNtp (unsigned __int64 *ptimeXX) {
SYSTEMTIME st;
GetSystemTime (&st);
union {
FILETIME ft;
unsigned __int64 ui64ft;
};
SystemTimeToFileTime (&st, &ft);
*ptimeXX = NtpTimeEpochFromNtTimeEpoch (ui64ft);
}
static int Exec (LPTHREAD_START_ROUTINE pfunc, void *pvControlBlock = NULL) {
HANDLE h = CreateThread (NULL, 0, pfunc, pvControlBlock, 0, NULL);
if (! h)
return GetLastError ();
WaitForSingleObject (h, INFINITE);
DWORD dw = ERROR_INTERNAL_ERROR;
GetExitCodeThread (h, &dw);
CloseHandle (h);
return (int)dw;
}
#if defined (DEBUG) || defined (_DEBUG)
static void DumpPacket (NTP_REQUEST *pPacket) {
unsigned int li = pPacket->li ();
unsigned int vn = pPacket->vn ();
unsigned int mode = pPacket->mode ();
unsigned int poll = pPacket->poll ();
unsigned int stratum = pPacket->stratum ();
unsigned int precision = pPacket->precision ();
unsigned int root_delay = pPacket->root_delay ();
unsigned int root_dispersion = pPacket->root_dispersion ();
unsigned int ref_id = pPacket->ref_id ();
unsigned __int64 ref_stamp = pPacket->ref_stamp ();
unsigned __int64 orig_stamp = pPacket->orig_stamp ();
unsigned __int64 recv_stamp = pPacket->recv_stamp ();
unsigned __int64 trans_stamp = pPacket->trans_stamp ();
DEBUGMSG(ZONE_PACKETS, (L"\r\nSNTP Packet:\r\n"));
WCHAR *pText = L"";
switch (li) {
case 0:
pText = L"No warning";
break;
case 1:
pText = L"Last minute has 61 seconds";
break;
case 2:
pText = L"Last minute has 59 seconds";
break;
case 3:
pText = L"Alarm condition (clock not synchronized)";
break;
default:
pText = L"Illegal or reserved code";
break;
}
DEBUGMSG(ZONE_PACKETS, (L"Leap : %d (%s)\r\n", li, pText));
DEBUGMSG(ZONE_PACKETS, (L"Version : %d\r\n", vn));
pText = L"";
switch (mode) {
case 1:
pText = L"symmetric active";
break;
case 2:
pText = L"symmetric passive";
break;
case 3:
pText = L"client";
break;
case 4:
pText = L"server";
break;
case 5:
pText = L"broadcast";
break;
case 6:
pText = L"NTP control";
break;
case 7:
pText = L"private use";
break;
default:
pText = L"illegal or reserved code";
break;
}
DEBUGMSG(ZONE_PACKETS, (L"Mode : %d (%s)\r\n", mode, pText));
DEBUGMSG(ZONE_PACKETS, (L"Stratum : %d\r\n", stratum));
DEBUGMSG(ZONE_PACKETS, (L"Poll : %d\r\n", poll));
DEBUGMSG(ZONE_PACKETS, (L"Precision : %d\r\n", poll));
DEBUGMSG(ZONE_PACKETS, (L"Root delay: 0x%08x (%d sec)\r\n", root_delay, ((int)root_delay)/4));
DEBUGMSG(ZONE_PACKETS, (L"Root disp : 0x%08x (%d sec)\r\n", root_dispersion, ((int)root_dispersion)/4));
in_addr ia;
ia.S_un.S_addr = ref_id;
DEBUGMSG(ZONE_PACKETS, (L"Refid : %08x (or %a)\r\n", ref_id, inet_ntoa (ia)));
union {
unsigned __int64 ui64;
FILETIME ft;
};
SYSTEMTIME xst;
ui64 = NtTimeEpochFromNtpTimeEpoch (ref_stamp);
FileTimeToSystemTime ((FILETIME *)&ui64, &xst);
DEBUGMSG(ZONE_PACKETS, (L"Reference time: %02d/%02d/%d %02d:%02d:%02d.%03d\n", xst.wMonth, xst.wDay, xst.wYear, xst.wHour, xst.wMinute, xst.wSecond, xst.wMilliseconds));
ui64 = NtTimeEpochFromNtpTimeEpoch (orig_stamp);
FileTimeToSystemTime ((FILETIME *)&ui64, &xst);
DEBUGMSG(ZONE_PACKETS, (L"Origination time: %02d/%02d/%d %02d:%02d:%02d.%03d\n", xst.wMonth, xst.wDay, xst.wYear, xst.wHour, xst.wMinute, xst.wSecond, xst.wMilliseconds));
ui64 = NtTimeEpochFromNtpTimeEpoch (recv_stamp);
FileTimeToSystemTime ((FILETIME *)&ui64, &xst);
DEBUGMSG(ZONE_PACKETS, (L"Received time: %02d/%02d/%d %02d:%02d:%02d.%03d\n", xst.wMonth, xst.wDay, xst.wYear, xst.wHour, xst.wMinute, xst.wSecond, xst.wMilliseconds));
ui64 = NtTimeEpochFromNtpTimeEpoch (trans_stamp);
FileTimeToSystemTime ((FILETIME *)&ui64, &xst);
DEBUGMSG(ZONE_PACKETS, (L"Transmitted time: %02d/%02d/%d %02d:%02d:%02d.%03d\n", xst.wMonth, xst.wDay, xst.wYear, xst.wHour, xst.wMinute, xst.wSecond, xst.wMilliseconds));
DEBUGMSG(ZONE_PACKETS, (L"\r\n\r\n"));
}
#endif
///////////////////////////////////////////////////////////////////////
//
// Threads
//
//
static DWORD WINAPI MulticastThread (LPVOID lpUnused) {
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Multicast Event\r\n"));
int fSuccess = FALSE;
if (! gpTS) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast: service not initialized!\r\n"));
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -