Skip to content

Instantly share code, notes, and snippets.

@icedac
Last active August 29, 2015 14:04
Show Gist options
  • Save icedac/15b232931b92ec6fb36b to your computer and use it in GitHub Desktop.
Save icedac/15b232931b92ec6fb36b to your computer and use it in GitHub Desktop.
// Timesync.cpp : time resync from NTP server
// ref: http://www.abnormal.com/~thogard/ntp/
// ref: http://stackoverflow.com/a/19815921
#include <winsock2.h>
#include <time.h>
#include <strsafe.h>
#pragma comment( lib, "ws2_32.lib" )
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>
#include <math.h>
//#include <sys/socket.h>
//#include <arpa/inet.h>
//#include <netinet/in.h>
//#include <netdb.h>
#define NTP_MODE_CLIENT 3
#define NTP_VERSION 3
#define TRANSMIT_TIME_OFFSET 40
#define REFERENCE_TIME_OFFSET 16
#define ORIGINATE_TIME_OFFSET 24
#define RECEIVE_TIME_OFFSET 32
//#define OFFSET_1900_TO_1970 ((uint64_t)((365 * 70) + 17) * 24 * 60 * 60)
#define OFFSET_1900_TO_1970 2208988800U
uint32_t read32(char* buffer, int offset) {
char b0 = buffer[offset];
char b1 = buffer[offset + 1];
char b2 = buffer[offset + 2];
char b3 = buffer[offset + 3];
// convert signed bytes to unsigned values
uint32_t i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
uint32_t i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
uint32_t i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
uint32_t i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
uint32_t v = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
return v;
}
uint64_t readTimeStamp(char *buffer, int offset) {
uint32_t seconds = read32(buffer, offset);
uint32_t fraction = read32(buffer, offset + 4);
uint64_t v = ((int64_t)seconds - OFFSET_1900_TO_1970) * 1000 + (int64_t)fraction * 1000 / (int64_t)0x100000000;
// printf ("%llu\n", v);
return v;
}
void writeTimeStamp(char* buffer, int offset, long long int time) {
uint64_t seconds = (time / 1000);
uint64_t milliseconds = time - (uint64_t)seconds * 1000;
seconds += OFFSET_1900_TO_1970;
// write seconds in big endian format
buffer[offset++] = (char)(seconds >> 24);
buffer[offset++] = (char)(seconds >> 16);
buffer[offset++] = (char)(seconds >> 8);
buffer[offset++] = (char)(seconds >> 0);
uint64_t fraction = ((uint64_t)milliseconds * 0x100000000 / 1000);
// write fraction in big endian format
buffer[offset++] = (char)(fraction >> 24);
buffer[offset++] = (char)(fraction >> 16);
buffer[offset++] = (char)(fraction >> 8);
// low order bits should be random data
buffer[offset++] = (char)(rand() * 255.0);
}
void ErrorExit( const TCHAR* functionName )
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)functionName) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
functionName, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
void print_time(int64_t milliseconds_from_1970 )
{
time_t tt = (milliseconds_from_1970 / 1000);
int msec = tt % 1000;
// printf("%s", ctime(&tt));
tm* t = localtime(&tt);
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", 1900+t->tm_year, 1+t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, msec );
}
int64_t ntpdate(const char* ntp_hostname)
{
const int NTP_PORT = 123; //NTP is port 123
const int MAXLEN = 1024; //check our buffers
int i; // misc var i
char msg[48];
memset(msg, 0, sizeof(msg));
msg[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
writeTimeStamp(msg, TRANSMIT_TIME_OFFSET, GetTickCount64());
char buf[MAXLEN] = { 0, }; // the buffer we get back
//struct in_addr ipaddr; //
struct protoent *proto; //
struct sockaddr_in server_addr;
int s; // socket
time_t tmit; // the time -- This is a time_t sort of
//use Socket;
//
//#we use the system call to open a UDP socket
//socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
proto = getprotobyname("udp");
if (nullptr == proto) ErrorExit(_T("getprotobyname"));
s = socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if (s == SOCKET_ERROR) ErrorExit(_T("socket"));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ntp_hostname);
server_addr.sin_port = htons(NTP_PORT);
/*
* build a message. Our message is all zeros except for a one in the
* protocol version field
* msg[] in binary is 00 001 000 00000000
* it should be a total of 48 bytes long
*/
DWORD tickStart = GetTickCount();
// send the data
i = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == i) ErrorExit(_T("sendto"));
// get the data back
i = recv(s, (char*)buf, sizeof(buf), 0);
if (-1 == i) ErrorExit(_T("recv"));
DWORD rtt = GetTickCount() - tickStart;
//We get 12 long words back in Network order
/*
for(i=0;i<12;i++)
printf("%d\t%-8x\n",i,ntohl(buf[i]));
*/
/*
* The high word of transmit time is the 10th word we get back
* tmit is the time in seconds not accounting for network delays which
* should be way less than a second if this is a local NTP server
*/
int64_t originateTime = readTimeStamp(buf, ORIGINATE_TIME_OFFSET);
int64_t receiveTime = readTimeStamp(buf, RECEIVE_TIME_OFFSET);
int64_t transmitTime = readTimeStamp(buf, TRANSMIT_TIME_OFFSET);
/*
print_time(transmitTime);
print_time(receiveTime);
print_time(transmitTime);
time_t tt = time(nullptr);
print_time(tt*1000);
*/
printf("Round trip time from %s is <%d> msec.\n", ntp_hostname, rtt);
int64_t transmitTime_with_rtt_adjust = transmitTime + (rtt / 2);
return transmitTime_with_rtt_adjust;
}
int _tmain(int argc, _TCHAR* argv[])
{
const WORD WINSOCK_VERSION_ID = 0x202;
WSADATA wsaData;
WSAStartup(WINSOCK_VERSION_ID, &wsaData);
//ntpdate("time-b.nist.gov"); = 129.6.15.29
const char* ntpserver_ip = "129.6.15.29";
int64_t tt_msec = ntpdate("129.6.15.29");
time_t tt = tt_msec / 1000;
int msec = tt_msec % 1000;
tm* t = nullptr;
t = localtime(&tt);
if (nullptr == t) ErrorExit(_T("localtime"));
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d[LOCAL] time from NTP[%s]\n", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, msec, ntpserver_ip);
t = gmtime(&tt);
if (nullptr == t) ErrorExit(_T("gmtime"));
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d[UTC+0] time from NTP[%s]\n", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, msec, ntpserver_ip);
SYSTEMTIME st;
GetLocalTime(&st);
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d[LOCAL] time from LOCAL\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
GetSystemTime(&st);
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d[UTC+0] time from LOCAL\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
st.wYear = 1900 + t->tm_year;
st.wMonth = 1 + t->tm_mon;
st.wDay = t->tm_mday;
st.wHour = t->tm_hour;
st.wMinute = t->tm_min;
st.wSecond = t->tm_sec;
st.wMilliseconds = msec;
BOOL success = SetSystemTime(&st);
if (!success) ErrorExit(_T("SetSystemTime"));
printf("Time setted from %s.\n", ntpserver_ip);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment