📄 sntp.cxx
字号:
gpTS->Lock ();
if (! gpTS->IsStarted ()) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: service not active!\r\n"));
gpTS->Unlock ();
return 0;
}
int fTimeAccurate = gpTS->IsTimeAccurate();
unsigned int uiPollInterval = gpTS->dwMulticastPeriodMS / 1000;
unsigned int poll = 1;
while (poll < uiPollInterval)
poll <<= 1;
poll >>= 1;
unsigned int ref = (unsigned int)gpTS->llLastSyncTimeXX & 0xffffffff;
unsigned __int64 ref_ts = gpTS->llLastSyncTimeXX;
gpTS->Unlock ();
if (! fTimeAccurate) {
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Multicast server does not have accurate time\r\n"));
return 0;
}
NTP_REQUEST dg;
memset (&dg, 0, sizeof(dg));
dg.set_vn (4);
dg.set_mode (5);
dg.set_stratum (2);
dg.set_poll (poll);
dg.set_precision((unsigned int)-7);
dg.set_ref_id (ref);
dg.set_ref_stamp (ref_ts);
int icast = 0;
for ( ; ; ) {
if (! gpTS) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast: service not initialized!\r\n"));
return 0;
}
gpTS->Lock ();
if (! gpTS->IsStarted ()) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast: service not active!\r\n"));
gpTS->Unlock ();
return 0;
}
if (icast >= gpTS->cMcasts)
break;
char hostname[DNS_MAX_NAME_BUFFER_LENGTH];
strcpy (hostname, gpTS->sntp_mcasts[icast++]);
gpTS->Unlock ();
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Multicast: multicasting to %a\r\n", hostname));
ADDRINFO aiHints;
ADDRINFO *paiLocal = NULL;
memset(&aiHints, 0, sizeof(aiHints));
aiHints.ai_family = PF_UNSPEC;
aiHints.ai_socktype = SOCK_DGRAM;
aiHints.ai_flags = 0; // Or AI_NUMERICHOST; ?
if (0 != getaddrinfo(hostname, NTP_PORT_A, &aiHints, &paiLocal)) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast: host %a is not reachable\r\n", hostname));
continue;
}
for (ADDRINFO *paiTrav = paiLocal; paiTrav ; paiTrav = paiTrav->ai_next) {
SOCKET s;
if (INVALID_SOCKET == (s = socket(paiTrav->ai_family, paiTrav->ai_socktype, paiTrav->ai_protocol)))
continue;
int on = 1;
if (0 != setsockopt (s, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on))) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast: could not set broadcast option, error %d\n", GetLastError ()));
}
unsigned __int64 llTXX;
GetCurrTimeNtp (&llTXX);
dg.set_trans_stamp (llTXX);
int iRet = sendto (s, (char *)&dg, sizeof(dg), 0, paiTrav->ai_addr, paiTrav->ai_addrlen);
closesocket (s);
if (sizeof(dg) == iRet)
break;
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Multicast failed: error %d; retrying different address family\n", GetLastError ()));
}
if (paiLocal)
freeaddrinfo(paiLocal);
}
if (gpTS->dwMulticastPeriodMS > 1000)
gpTS->ckNextMulticast = gpTS->pEvents->ScheduleEvent (MulticastThread, NULL, gpTS->dwMulticastPeriodMS);
gpTS->Unlock ();
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Multicast event processing completed\r\n"));
return 0;
}
static int GetOffsetFromServer (char *hostname, __int64 *pllOffset) {
ADDRINFO aiHints;
ADDRINFO *paiLocal = NULL;
memset(&aiHints, 0, sizeof(aiHints));
aiHints.ai_family = PF_UNSPEC;
aiHints.ai_socktype = SOCK_DGRAM;
aiHints.ai_flags = 0; // Or AI_NUMERICHOST; ?
if (0 != getaddrinfo(hostname, NTP_PORT_A, &aiHints, &paiLocal)) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: host %a is not reachable\r\n", hostname));
return FALSE;
}
for (ADDRINFO *paiTrav = paiLocal; paiTrav ; paiTrav = paiTrav->ai_next) {
SOCKET s;
if (INVALID_SOCKET == (s = socket(paiTrav->ai_family, paiTrav->ai_socktype, paiTrav->ai_protocol)))
continue;
for (int i = 0 ; i < 3 ; ++i) {
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh: querying server %a\r\n", hostname));
NTP_REQUEST dg;
memset (&dg, 0, sizeof(dg));
dg.set_vn (4);
dg.set_mode (3);
unsigned __int64 llT1XX;
GetCurrTimeNtp (&llT1XX);
dg.set_trans_stamp (llT1XX);
#if defined (DEBUG) || defined (_DEBUG)
DEBUGMSG (ZONE_PACKETS, (L"[TIMESVC] Sending SNTP request\r\n"));
DumpPacket (&dg);
#endif
if (sizeof (dg) == sendto (s, (char *)&dg, sizeof(dg), 0, paiTrav->ai_addr, paiTrav->ai_addrlen)) {
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh: sent request, awaiting response\r\n"));
fd_set f;
FD_ZERO (&f);
FD_SET (s, &f);
timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select (0, &f, NULL, NULL, &tv) > 0) {
SOCKADDR_STORAGE sa;
int salen = sizeof(sa);
if (sizeof(dg) == recvfrom (s, (char *)&dg, sizeof(dg), 0, (sockaddr *)&sa, &salen)) {
unsigned __int64 llT4XX;
GetCurrTimeNtp (&llT4XX);
#if defined (DEBUG) || defined (_DEBUG)
DEBUGMSG (ZONE_PACKETS, (L"[TIMESVC] Received SNTP response\r\n"));
DumpPacket (&dg);
#endif
int fSuccess = FALSE;
if ((dg.li () != 3) && (llT1XX == dg.orig_stamp ())) {
unsigned __int64 llT2XX = dg.recv_stamp ();
unsigned __int64 llT3XX = dg.trans_stamp ();
unsigned __int64 llT1 = NtTimeEpochFromNtpTimeEpoch (llT1XX);
unsigned __int64 llT2 = NtTimeEpochFromNtpTimeEpoch (llT2XX);
unsigned __int64 llT3 = NtTimeEpochFromNtpTimeEpoch (llT3XX);
unsigned __int64 llT4 = NtTimeEpochFromNtpTimeEpoch (llT4XX);
*pllOffset = ((__int64)((llT2 - llT1) + (llT3 - llT4))) / 2;
fSuccess = TRUE;
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: sntp server not synchronized\r\n"));
}
closesocket (s);
if (paiLocal)
freeaddrinfo(paiLocal);
return fSuccess;
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: sntp server datagram size incorrect (or authentication requested)\r\n"));
}
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: sntp server response timeout (no SNTP on server?)\r\n"));
}
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: host %a unreachable\r\n", hostname));
}
closesocket (s);
}
}
if (paiLocal)
freeaddrinfo(paiLocal);
return FALSE;
}
static int RefreshTimeFromServer (char *hostname, int fForceTime, DWORD dwMaxAdjustS, int *pfTimeChanged) {
*pfTimeChanged = FALSE;
__int64 llOffset;
if (GetOffsetFromServer (hostname, &llOffset)) {
int iOffsetSec = (int)(llOffset / 10000000);
if (fForceTime || ((DWORD)abs (iOffsetSec) < dwMaxAdjustS)) {
SYSTEMTIME st, st2;
unsigned __int64 llTime;
GetSystemTime (&st);
SystemTimeToFileTime (&st, (FILETIME *)&llTime);
llTime += llOffset;
FileTimeToSystemTime ((FILETIME *)&llTime, &st2);
// The system must be updated with whether we're DST or STD
// before we update the system clock. We're updating in UTC
// but system clock will convert and save this as local time,
// which means it will apply the DST/STD bias first.
SetDaylightOrStandardTimeDST(&st2);
SetSystemTime (&st2);
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh: time accepted. offset = %d s.\r\n", iOffsetSec));
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh: old time: %02d/%02d/%d %02d:%02d:%02d.%03d\r\n", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds));
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh: new time: %02d/%02d/%d %02d:%02d:%02d.%03d\r\n", st2.wMonth, st2.wDay, st2.wYear, st2.wHour, st2.wMinute, st2.wSecond, st2.wMilliseconds));
if ((DWORD)abs (iOffsetSec) > MIN_TIMEUPDATE)
*pfTimeChanged = TRUE;
return TRUE;
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: time indicated by server is not within allowed adjustment boundaries (offset = %d s)\r\n", iOffsetSec));
}
}
return FALSE;
}
static DWORD WINAPI TimeRefreshThread (LPVOID lpUnused) {
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Refresh Event\r\n"));
int fSuccess = FALSE;
int fTimeChanged = FALSE;
int iSrv = 0;
while (! fSuccess) {
if (! gpTS) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: service not initialized!\r\n"));
return 0;
}
gpTS->Lock ();
if (! gpTS->IsStarted ()) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh: service not active!\r\n"));
gpTS->Unlock ();
return 0;
}
if (iSrv >= gpTS->cServers) {
DEBUGMSG(ZONE_WARNING, (L"[TIMESVC] Time Refresh: all servers queried, but time not updated.\r\n"));
gpTS->Unlock ();
break;
}
int fForceTime = gpTS->fForceTimeToServer;
DWORD dwMaxAdjustS = gpTS->dwAdjustThreshMS / 1000;
char hostname[DNS_MAX_NAME_BUFFER_LENGTH];
memcpy (hostname, gpTS->sntp_servers[iSrv++], sizeof(hostname));
gpTS->Unlock ();
fSuccess = RefreshTimeFromServer (hostname, fForceTime, dwMaxAdjustS, &fTimeChanged);
}
if (gpTS) {
gpTS->Lock ();
if (gpTS->IsStarted ()) {
if (fSuccess) {
GetCurrTimeNtp (&gpTS->llLastSyncTimeXX);
gpTS->fRefreshRequired = FALSE;
gpTS->UpdateNowOrLater (Later);
gpTS->fForceTimeToServer = FALSE;
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time successfully refreshed\r\n"));
if (fTimeChanged || (gpTS->ckNextMulticast == 0))
gpTS->TimeChanged ();
} else {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Time Refresh failed, rescheduling\r\n"));
gpTS->fRefreshRequired = TRUE;
gpTS->UpdateNowOrLater (Shortly);
if(gpTS->ckNextMulticast == 0)
gpTS->TimeChanged();
}
}
gpTS->Unlock ();
}
DEBUGMSG(ZONE_CLIENT, (L"[TIMESVC] Time Refresh event processing completed\r\n"));
return 0;
}
static DWORD WINAPI RxThread (LPVOID lpUnused) {
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Server thread started\r\n"));
for ( ; ; ) {
if (! gpTS) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Server: Not initialized, quitting\r\n"));
return 0;
}
gpTS->Lock ();
if (! gpTS->IsStarted ()) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Server: Not active, quitting\r\n"));
gpTS->Unlock ();
return 0;
}
fd_set sockSet;
FD_ZERO(&sockSet);
for (int i = 0; i < gpTS->iSock; ++i)
FD_SET(gpTS->saServer[i], &sockSet);
gpTS->Unlock ();
int iSockReady = select (0,&sockSet,NULL,NULL,NULL);
if (iSockReady == 0 || iSockReady == SOCKET_ERROR) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Server: select failed, error=%d\r\n", GetLastError ()));
break;
}
for (i = 0; i < iSockReady; ++i) {
NTP_REQUEST dg;
SOCKADDR_STORAGE sa;
int salen = sizeof(sa);
int iRecv = recvfrom (sockSet.fd_array[i], (char *)&dg, sizeof(dg), 0, (sockaddr *)&sa, &salen);
if (iRecv <= 0) {
DEBUGMSG(ZONE_ERROR, (L"[TIMESVC] Server: receive failed, error=%d\r\n", GetLastError ()));
break;
}
if (iRecv != sizeof(dg)) {
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Server: size mismatch, packet ignored\r\n"));
continue;
}
#if defined (DEBUG) || defined (_DEBUG)
DEBUGMSG(ZONE_PACKETS, (L"[TIMESVC] Received SNTP request\r\n"));
DumpPacket (&dg);
#endif
if (dg.mode () == 3) { //client
dg.set_mode (4); //server
} else if (dg.mode () == 1) { // symmetric, active
dg.set_mode(1); // symmetric, passive
} else {
DEBUGMSG(ZONE_SERVER, (L"[TIMESVC] Server: Not a request, aborting\r\n"));
continue;
}
dg.set_root_delay (0);
dg.set_root_dispersion (0);
dg.set_precision((unsigned int)-7);
unsigned __int64 llOrigTimeXX = dg.trans_stamp ();
dg.set_orig_stamp (llOrigTimeXX);
unsigned __int64 llRecvTimeXX;
GetCurrTimeNtp (&llRecvTimeXX);
dg.set_recv_stamp (llRecvTimeXX);
dg.set_trans_stamp (llRecvTimeXX);
if (! gpTS)
break;
gpTS->Lock ();
dg.set_ref_stamp (gpTS->llLastSyncTimeXX);
dg.set_ref_id ((unsigned int)gpTS->llLastSyncTimeXX);
if (gpTS->IsTimeAccurate()) {
dg.set_li (0);
dg.set_stratum (2);
} else {
dg.set_li (3);
dg.set_stratum (15);
}
gpTS->Unlock ();
sendto (sockSet.fd_array[i], (char *)&dg, sizeof(dg), 0, (sockaddr *)&sa, salen);
#if defined (DEBUG) || defined (_DEBUG)
DEBUGMSG(ZONE_PACKETS, (L"[TIMESVC] Sent SNTP response\r\n"));
DumpPacket (&dg);
#endif
}
}
DEBUGMSG(ZONE_INIT, (L"[TIMESVC] Server Thread exited\r\n"));
return 0;
}
///////////////////////////////////////////////////////////////////////
//
// Interface, initialization, management
//
//
static DWORD WINAPI SyncTime (LPVOID dwUnused) {
DEBUGMSG(ZONE_TRACE, (L"[TIMESVC] Time update request from OS\r\n"));
int iErr = ERROR_SERVICE_DOES_NOT_EXIST;
if (gpTS) {
gpTS->Lock ();
iErr = ERROR_SUCCESS;
if (! gpTS->IsStarted())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -