最简单的嵌入式Linux下ntp实现
2019-07-12 15:35发布
生成海报
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */
#define NTP_PORT (123)
/* How to multiply by 4294.967296 quickly (and not quite exactly)
* without using floating point or greater than 32-bit integers.
* If you want to fix the last 12 microseconds of error, add in
* (2911*(x))>>28)
*/
#define NTPFRAC(x) ( 4294*(x) + ( (1981*(x))>>11 ) )
/* The reverse of the above, needed if we want to set our microsecond
* clock (via settimeofday) based on the incoming time in NTP format.
* Basically exact.
*/
#define USEC(x) ( ( (x) >> 12 ) - 759 * ( ( ( (x) >> 10 ) + 32768 ) >> 16 ) )
/* Converts NTP delay and dispersion, apparently in seconds scaled
* by 65536, to microseconds. RFC1305 states this time is in seconds,
* doesn't mention the scaling.
* Should somehow be the same as 1000000 * x / 65536
*/
#define sec2u(x) ( (x) * 15.2587890625 )
typedef u_int32_t __u32;
struct ntptime {
unsigned int coarse;
unsigned int fine;
};
void send_packet(int usd)
{
__u32 data[12];
struct timeval now;
#define LI 0
#define VN 3
#define MODE 3
#define STRATUM 0
#define POLL 4
#define PREC -6
bzero((char *) data,sizeof(data));
data[0] = htonl (
( LI << 30 ) | ( VN << 27 ) | ( MODE << 24 ) |
( STRATUM << 16) | ( POLL << 8 ) | ( PREC & 0xff ) );
data[1] = htonl(1<<16); /* Root Delay (seconds) */
data[2] = htonl(1<<16); /* Root Dispersion (seconds) */
gettimeofday(&now,NULL);
data[10] = htonl(now.tv_sec + JAN_1970); /* Transmit Timestamp coarse */
data[11] = htonl(NTPFRAC(now.tv_usec)); /* Transmit Timestamp fine */
send(usd,data,48,0);
}
/*
double ntpdiff( struct ntptime *start, struct ntptime *stop)
{
int a;
unsigned int b;
a = stop->coarse - start->coarse;
if (stop->fine >= start->fine) {
b = stop->fine - start->fine;
} else {
b = start->fine - stop->fine;
b = ~b;
a -= 1;
}
return a*1.e6 + b * (1.e6/4294967296.0);
}
*/
void rfc1305(uint32_t *data)
{
/*
struct ntptime *arrival;
struct timeval udp_arrival;
gettimeofday(&udp_arrival, NULL);
arrival->coarse = udp_arrival.tv_sec + JAN_1970;
arrival->fine = NTPFRAC(udp_arrival.tv_usec);
*/
/*
// straight out of RFC-1305 Appendix A
int li, vn, mode, stratum, poll, prec;
int delay, disp, refid;
struct ntptime reftime, orgtime, rectime, xmttime;
#define Data(i) ntohl(((uint32_t *)data)[i])
li = Data(0) >> 30 & 0x03;
vn = Data(0) >> 27 & 0x07;
mode = Data(0) >> 24 & 0x07;
stratum = Data(0) >> 16 & 0xff;
poll = Data(0) >> 8 & 0xff;
prec = Data(0) & 0xff;
if (prec & 0x80) prec|=0xffffff00;
delay = Data(1);
disp = Data(2);
refid = Data(3);
reftime.coarse = Data(4);
reftime.fine = Data(5);
orgtime.coarse = Data(6);
orgtime.fine = Data(7);
rectime.coarse = Data(8);
rectime.fine = Data(9);
xmttime.coarse = Data(10);
xmttime.fine = Data(11);
#undef Data
struct timeval tv_set;
// it would be even better to subtract half the slop
tv_set.tv_sec = xmttime.coarse - JAN_1970;
// divide xmttime.fine by 4294.967296
tv_set.tv_usec = USEC(xmttime.fine);
if (settimeofday(&tv_set,NULL)<0) {
perror("settimeofday");
exit(1);
}
*/
struct timeval tv_set;
tv_set.tv_sec = ntohl(((uint32_t *)data)[10]) - JAN_1970;
tv_set.tv_usec = USEC(ntohl(((uint32_t *)data)[11]));
if (settimeofday(&tv_set, NULL) < 0) {
perror("settimeofday");
exit(1);
}
/*
double el_time,st_time;
el_time=ntpdiff(&orgtime,arrival); // elapsed
st_time=ntpdiff(&rectime,&xmttime); // stall
return(el_time-st_time);
*/
}
int main(int argc, char *argv[])
{
int usd;
struct sockaddr_in sa;
struct hostent *he;
struct timeval tv;
fd_set fds;
int i;
char *srv;
char buf[256];
// printf("mini ntpclient
");
if (argc <= 1) {
printf("Usage: %s [server [...]]
", argv[0]);
return 1;
}
for (i = 1; i < argc; ++i) {
// ntp.c passes servers as one block of string, so we need to break it down
strcpy(buf, argv[i]);
srv = strtok(buf, " ");
while (srv) {
if ((usd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
printf("socket error");
return 1;
}
if ((he = gethostbyname(srv)) != NULL) {
memset(&sa, 0, sizeof(sa));
memcpy(&sa.sin_addr, he->h_addr_list[0], sizeof(sa.sin_addr));
sa.sin_port = htons(NTP_PORT);
sa.sin_family = AF_INET;
//printf("trying %s [%s]
", argv[i], inet_ntoa(sa.sin_addr));
if (connect(usd, (struct sockaddr*)&sa, sizeof(sa)) != -1) {
send_packet(usd);
tv.tv_sec = 3;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(usd, &fds);
if (select(usd + 1, &fds, NULL, NULL, &tv) == 1) {
int len;
uint32_t packet[12];
len = recv(usd, packet, sizeof(packet), 0);
if (len == sizeof(packet)) {
rfc1305(packet);
close(usd);
printf("Time_updated.
");
return 0;
}
}
}
else {
perror("connect");
printf("connect_error
");
}
}
else {
perror("gethostbyname");
printf("gethostbyname_error
");
}
close(usd);
srv = strtok(NULL, " ");
}
}
return 1;
}
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮