?? ntpclient.c
字號:
/* * ntpclient.c - NTP client * * Copyright 1997, 1999, 2000 Larry Doolittle <larry@doolittle.boa.org> * Last hack: 2 December, 2000 * * 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: * - Double check that the originate timestamp in the received packet * corresponds to what we sent. * - Verify that the return packet came from the host we think * we're talking to. Not necessarily useful since UDP packets * are so easy to forge. * - Complete phase locking code. * - Write more documentation :-( * * Compile with -D_PRECISION_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 "XXXX fixme - non-automatic build configuration". */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#include <time.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#ifdef _PRECISION_SIOCGSTAMP#include <sys/ioctl.h>#endif#define ENABLE_DEBUG#define HOSTNAME_MAX_LEN 64extern char *optarg;/* XXXX fixme - non-automatic build configuration */#ifdef linux#include <sys/utsname.h>#include <sys/time.h>typedef u_int32_t __u32;#include <sys/timex.h>#else#define main ntpclientextern 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)typedef uint32_t __u32;#endif#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 )struct ntptime { unsigned int coarse; unsigned int fine;};void send_packet(int usd, int print_errors);int rfc1305print(char *data, struct ntptime *arrival);int udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len);/* global variables (I know, bad form, but this is a short program) */char incoming[1500];struct timeval time_of_send;int live=0;int set_clock=0; /* non-zero presumably needs root privs */int host_count = 0;int current_host = 0;char *host_list[8];struct addrinfo *addr_list = NULL;struct addrinfo *current_addr = NULL;char **global_argv;#ifdef ENABLE_DEBUGint debug=0;#define DEBUG_OPTION "d"#else#define debug 0#define DEBUG_OPTION#endifint contemplate_data(unsigned int absolute, double skew, double errorbar, int freq);int get_current_freq(){ /* 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}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}int resolv_conf_changed(void){ struct stat st; static time_t last_mod; static int last_mod_valid = 0; int ret; if (stat("/etc/resolv.conf", &st) < 0) { last_mod_valid = 0; return 0; } ret = !last_mod_valid || last_mod != st.st_mtime; last_mod_valid = 1; last_mod = st.st_mtime; return ret;}char *make_addr(struct sockaddr *addr){ static char tmp[128]; int port; switch (addr->sa_family) { case AF_INET: inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, tmp, sizeof(tmp)); port = ((struct sockaddr_in *)addr)->sin_port; break; case AF_INET6: inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, tmp, sizeof(tmp)); port = ((struct sockaddr_in6 *)addr)->sin6_port; break; default: tmp[0] = 0; return tmp; } sprintf(tmp + strlen(tmp), ":%d", ntohs(port)); return tmp;}void server_failed(void){ if (current_addr) current_addr = current_addr->ai_next;}void send_packet(int usd, int print_errors){ __u32 data[12]; struct timeval now; struct addrinfo *addr; int res; struct addrinfo hints; static int wrapped = 0; if (!current_addr) { if (current_host == host_count) { if (wrapped) { if (resolv_conf_changed()) { /* glibc only reads resolv.conf once, * so we need to re-exec to pick up * the new nameservers */ if (debug) printf("resolv.conf changed; " "re-execing\n"); execvp(global_argv[0], global_argv); } /* skip this query, continue retrying */ wrapped = 0; return; } wrapped = 1; current_host = 0; } if (addr_list) freeaddrinfo(addr_list); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; res = getaddrinfo(host_list[current_host], NTP_PORT, &hints, &addr_list); if (res) { if (print_errors) fprintf(stderr, "%s: %s\n", host_list[current_host], gai_strerror(res)); ++current_host; send_packet(usd, print_errors); return; } current_addr = addr_list; if (debug) for (addr = addr_list; addr; addr = addr->ai_next) printf("adding %s\n", make_addr(addr->ai_addr)); ++current_host; send_packet(usd, print_errors); return; } wrapped = 0;#define LI 0#define VN 3#define MODE 3#define STRATUM 0#define POLL 4 #define PREC -6 if (debug) fprintf(stderr,"Sending to %s...\n", make_addr(current_addr->ai_addr)); if (sizeof(data) != 48) { fprintf(stderr,"size error\n"); return; } 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 */ if (sendto(usd,data,48,0,current_addr->ai_addr, current_addr->ai_addrlen) < 0) server_failed(); time_of_send=now;}int udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len){ struct timeval udp_arrival; struct ntptime udp_arrival_ntp;#ifdef _PRECISION_SIOCGSTAMP if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) { perror("ioctl-SIOCGSTAMP"); gettimeofday(&udp_arrival,NULL); }#else gettimeofday(&udp_arrival,NULL);#endif udp_arrival_ntp.coarse = udp_arrival.tv_sec + JAN_1970; udp_arrival_ntp.fine = NTPFRAC(udp_arrival.tv_usec); if (debug) { printf("packet of length %d received\n",data_len); printf("Source: %s\n", make_addr(sa_source)); } if (rfc1305print(data,&udp_arrival_ntp) < 0) { if (debug) printf("kiss of death! removing %s...\n", make_addr(sa_source)); return -1; } return 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);}int rfc1305print(char *data, struct ntptime *arrival){/* straight out of RFC-1305 Appendix A */ int li, vn, mode, stratum, poll, prec; int delay, disp, refid; struct ntptime reftime, orgtime, rectime, xmttime;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -