最简单的嵌入式Linux下ntp实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <sys/timex.h>

#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\n");

	if (argc <= 1) {
		printf("Usage: %s <server> [server [...]]\n", 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]\n", 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.\n");
							return 0;
						}
					}
				}
				else {
					perror("connect");
					printf("connect_error\n");
				}
			}
			else {
				perror("gethostbyname");
				printf("gethostbyname_error\n");
			}
			close(usd);
	
			srv = strtok(NULL, " ");
		}
	}

	return 1;
}



  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值