⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntpclient.c

📁 实现linux系统和网络时钟服务器的时间同步,从而可以得到准确的时间.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ntpclient.c - NTP client * * Copyright 1997, 1999, 2000, 2003, 2006, 2007  Larry Doolittle  <larry@doolittle.boa.org> * Last hack: December 30, 2007 * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License (Version 2, *  June 1991) as published by the Free Software Foundation.  At the *  time of writing, that license was published by the FSF with the URL *  http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by *  reference. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  Possible future improvements: *      - Write more documentation  :-( *      - Support leap second processing *      - Support IPv6 *      - Support multiple (interleaved) servers * *  Compile with -DPRECISION_SIOCGSTAMP if your machine really has it. *  There are patches floating around to add this to Linux, but *  usually you only get an answer to the nearest jiffy. *  Hint for Linux hacker wannabes: look at the usage of get_fast_time() *  in net/core/dev.c, and its definition in kernel/time.c . * *  If the compile gives you any flak, check below in the section *  labelled "XXX fixme - non-automatic build configuration". */#define _POSIX_C_SOURCE 199309#ifdef USE_OBSOLETE_GETTIMEOFDAY#define _BSD_SOURCE#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>     /* gethostbyname */#include <arpa/inet.h>#include <time.h>#include <unistd.h>#include <errno.h>#ifdef PRECISION_SIOCGSTAMP#include <sys/ioctl.h>#endif#ifdef USE_OBSOLETE_GETTIMEOFDAY#include <sys/time.h>#endif#include "ntpclient.h"/* Default to the RFC-4330 specified value */#ifndef MIN_INTERVAL#define MIN_INTERVAL 15#endif#ifdef ENABLE_DEBUG#define DEBUG_OPTION "d"int debug=0;#else#define DEBUG_OPTION#endif#ifdef ENABLE_REPLAY#define  REPLAY_OPTION   "r"#else#define  REPLAY_OPTION#endifextern char *optarg;  /* according to man 2 getopt */#include <stdint.h>typedef uint32_t u32;  /* universal for C99 *//* typedef u_int32_t u32;   older Linux installs? *//* XXX fixme - non-automatic build configuration */#ifdef __linux__#include <sys/utsname.h>#include <sys/time.h>#include <sys/timex.h>#elseextern struct hostent *gethostbyname(const char *name);extern int h_errno;#define herror(hostname) \	fprintf(stderr,"Error %d looking up hostname %s\n", h_errno,hostname)#endif/* end configuration for host systems */#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 clock_settime) 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.  RFC-1305 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 )struct ntptime {	unsigned int coarse;	unsigned int fine;};struct ntp_control {	u32 time_of_send[2];	int live;	int set_clock;   /* non-zero presumably needs root privs */	int probe_count;	int cycle_time;	int goodness;	int cross_check;	char serv_addr[4];};/* prototypes for some local routines */static void send_packet(int usd, u32 time_sent[2]);static int rfc1305print(u32 *data, struct ntptime *arrival, struct ntp_control *ntpc, int *error);/* static void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len); */static int get_current_freq(void){	/* OS dependent routine to get the current value of clock frequency.	 */#ifdef __linux__	struct timex txc;	txc.modes=0;	if (__adjtimex(&txc) < 0) {		perror("adjtimex"); exit(1);	}	return txc.freq;#else	return 0;#endif}static int set_freq(int new_freq){	/* OS dependent routine to set a new value of clock frequency.	 */#ifdef __linux__	struct timex txc;	txc.modes = ADJ_FREQUENCY;	txc.freq = new_freq;	if (__adjtimex(&txc) < 0) {		perror("adjtimex"); exit(1);	}	return txc.freq;#else	return 0;#endif}static void set_time(struct ntptime *new){#ifndef USE_OBSOLETE_GETTIMEOFDAY	/* POSIX 1003.1-2001 way to set the system clock	 */	struct timespec tv_set;	/* it would be even better to subtract half the slop */	tv_set.tv_sec  = new->coarse - JAN_1970;	/* divide xmttime.fine by 4294.967296 */	tv_set.tv_nsec = USEC(new->fine)*1000;	if (clock_settime(CLOCK_REALTIME, &tv_set)<0) {		perror("clock_settime");		exit(1);	}	if (debug) {		printf("set time to %lu.%.9lu\n", tv_set.tv_sec, tv_set.tv_nsec);	}#else	/* Traditional Linux way to set the system clock	 */	struct timeval tv_set;	/* it would be even better to subtract half the slop */	tv_set.tv_sec  = new->coarse - JAN_1970;	/* divide xmttime.fine by 4294.967296 */	tv_set.tv_usec = USEC(new->fine);	if (settimeofday(&tv_set,NULL)<0) {		perror("settimeofday");		exit(1);	}	if (debug) {		printf("set time to %lu.%.6lu\n", tv_set.tv_sec, tv_set.tv_usec);	}#endif}static void ntpc_gettime(u32 *time_coarse, u32 *time_fine){#ifndef USE_OBSOLETE_GETTIMEOFDAY	/* POSIX 1003.1-2001 way to get the system time	 */	struct timespec now;	clock_gettime(CLOCK_REALTIME, &now);	*time_coarse = now.tv_sec + JAN_1970;	*time_fine   = NTPFRAC(now.tv_nsec/1000);#else	/* Traditional Linux way to get the system time	 */	struct timeval now;	gettimeofday(&now, NULL);	*time_coarse = now.tv_sec + JAN_1970;	*time_fine   = NTPFRAC(now.tv_usec);#endif}static void send_packet(int usd, u32 time_sent[2]){	u32 data[12];#define LI 0#define VN 3#define MODE 3#define STRATUM 0#define POLL 4#define PREC -6	if (debug) fprintf(stderr,"Sending ...\n");	if (sizeof data != 48) {		fprintf(stderr,"size error\n");		return;	}	memset(data,0,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) */	ntpc_gettime(time_sent, time_sent+1);	data[10] = htonl(time_sent[0]); /* Transmit Timestamp coarse */	data[11] = htonl(time_sent[1]); /* Transmit Timestamp fine   */	send(usd,data,48,0);}static void get_packet_timestamp(int usd, struct ntptime *udp_arrival_ntp){#ifdef PRECISION_SIOCGSTAMP	/* XXX broken */	struct timeval udp_arrival;	if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) {		perror("ioctl-SIOCGSTAMP");		gettimeofday(&udp_arrival,NULL);	}	udp_arrival_ntp->coarse = udp_arrival.tv_sec + JAN_1970;	udp_arrival_ntp->fine   = NTPFRAC(udp_arrival.tv_usec);#else	(void) usd;  /* not used */	ntpc_gettime(&udp_arrival_ntp->coarse, &udp_arrival_ntp->fine);#endif}static int check_source(int data_len, struct sockaddr *sa_source, unsigned int sa_len, struct ntp_control *ntpc){	struct sockaddr_in *sa_in=(struct sockaddr_in *)sa_source;	(void) sa_len;  /* not used */	if (debug) {		printf("packet of length %d received\n",data_len);		if (sa_source->sa_family==AF_INET) {			printf("Source: INET Port %d host %s\n",				ntohs(sa_in->sin_port),inet_ntoa(sa_in->sin_addr));		} else {			printf("Source: Address family %d\n",sa_source->sa_family);		}	}	/* we could check that the source is the server we expect, but	 * Denis Vlasenko recommends against it: multihomed hosts get it	 * wrong too often. */#if 0	if (memcmp(ntpc->serv_addr, &(sa_in->sin_addr), 4)!=0) {		return 1;  /* fault */	}#else	(void) ntpc; /* not used */#endif	if (NTP_PORT != ntohs(sa_in->sin_port)) {		return 1;  /* fault */	}	return 0;}static 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);}/* Does more than print, so this name is bogus. * It also makes time adjustments, both sudden (-s) * and phase-locking (-l). * sets *error to the number of microseconds uncertainty in answer * returns 0 normally, 1 if the message fails sanity checks */static int rfc1305print(u32 *data, struct ntptime *arrival, struct ntp_control *ntpc, int *error){/* straight out of RFC-1305 Appendix A */	int li, vn, mode, stratum, poll, prec;	int delay, disp, refid;	struct ntptime reftime, orgtime, rectime, xmttime;	double el_time,st_time,skew1,skew2;	int freq;#ifdef ENABLE_DEBUG	const char *drop_reason=NULL;#endif#define Data(i) ntohl(((u32 *)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	if (debug) {	printf("LI=%d  VN=%d  Mode=%d  Stratum=%d  Poll=%d  Precision=%d\n",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -