1: #ifndef lint 2: static char *rcsid = "$Source: /usr/users/louie/ntp/RCS/ntp.c,v $ $Revision: 3.4.1.6 $ $Date: 89/05/18 18:21:29 $"; 3: #endif lint 4: 5: /* 6: * $Log: ntp.c,v $ 7: * Revision 3.4.1.6 89/05/18 18:21:29 louie 8: * A few cosmetic changes in ntp.c for the case when udp/ntp is not in the 9: * /etc/services file. 10: * 11: * Revision 3.4.1.5 89/05/03 15:09:53 louie 12: * Fix minor problem in ntp.c to get sin_family set in the proper place. 13: * 14: * Revision 3.4.1.4 89/04/07 18:04:49 louie 15: * Removed unused variables from ntp.c program. 16: * 17: * Revision 3.4.1.3 89/03/22 18:29:22 louie 18: * patch3: Use new RCS headers. 19: * 20: * Revision 3.4.1.2 89/03/22 17:51:13 louie 21: * Use a connect UDP socket so we can pick up ICMP error messages. 22: * 23: * Revision 3.4.1.1 89/03/20 00:02:32 louie 24: * patch1: Shorten timeout interval and clean up timeout message. 25: * 26: * Revision 3.4 89/03/17 18:36:54 louie 27: * Latest test release. 28: * 29: * Revision 3.3.1.1 89/03/17 18:23:14 louie 30: * Fix code that sets time. 31: * 32: * Revision 3.3 89/03/15 14:19:30 louie 33: * New baseline for next release. 34: * 35: * Revision 3.2.1.2 89/03/15 13:45:13 louie 36: * Fix use of NTP_PORT when getservbyname() fails. Use "%f" in printf format 37: * strings rather than "%lf". 38: * 39: * 40: * Revision 3.2.1.1 89/03/10 11:26:23 louie 41: * Add (primitive) facility to set the time from an NTP timer server, 42: * much the same way as various UDP/TIME based programs do. The 43: * default output format is a one line listing of delay, offset and time. The 44: * previous, longer format can be had by using the -v option. 45: * 46: * Revision 3.2 89/03/07 18:20:55 louie 47: * Cleaned up displays of NTP header fields, also dumping in useful formats 48: * (floating point and ctime strings) as well as hex fields. 49: * 50: * Revision 3.1.1.1 89/02/15 08:53:30 louie 51: * Bug fixes to last released version. 52: * 53: * 54: * Revision 3.1 89/01/30 14:43:05 louie 55: * Second UNIX NTP test release. 56: * 57: * Revision 3.0 88/12/12 15:56:10 louie 58: * Test release of new UNIX NTP software. This version should conform to the 59: * revised NTP protocol specification. 60: * 61: */ 62: 63: /* 64: * This program expects a list of host names. It will send off a 65: * network time protocol packet and print out the replies on the 66: * terminal. 67: * 68: * Example: 69: * 70: * % ntp umd1.umd.edu 71: * Packet from: [128.8.10.1] 72: * Leap 0, version 1, mode Server, poll 6, precision -10 stratum 1 (WWVB) 73: * Synch Distance is 0000.1999 0.099991 74: * Synch Dispersion is 0000.0000 0.000000 75: * Reference Timestamp is a7bea6c3.88b40000 Tue Mar 7 14:06:43 1989 76: * Originate Timestamp is a7bea6d7.d7e6e652 Tue Mar 7 14:07:03 1989 77: * Receive Timestamp is a7bea6d7.cf1a0000 Tue Mar 7 14:07:03 1989 78: * Transmit Timestamp is a7bea6d8.0ccc0000 Tue Mar 7 14:07:04 1989 79: * Input Timestamp is a7bea6d8.1a77e5ea Tue Mar 7 14:07:04 1989 80: * umd1: delay:0.019028 offset:-0.043890 81: * Tue Mar 7 14:07:04 1989 82: * 83: */ 84: 85: #include <stdio.h> 86: #include <sys/types.h> 87: #include <sys/param.h> 88: #include <sys/time.h> 89: #include <sys/uio.h> 90: #include <sys/socket.h> 91: #include <sys/ioctl.h> 92: 93: #include <netinet/in.h> 94: #include <netinet/in_systm.h> 95: #include <netinet/ip.h> 96: #include <netinet/udp.h> 97: 98: #include <arpa/inet.h> 99: #include <netdb.h> 100: #include <strings.h> 101: #include <errno.h> 102: #include "ntp.h" 103: 104: char *modename[8] = { 105: "Unspecified", 106: "Symmetric Active", 107: "Symmetric Passive", 108: "Client", 109: "Server", 110: "Broadcast", 111: "Reserved-1", 112: "Reserved-2" 113: }; 114: 115: #define RETRY_COUNT 2 /* number of times we want to retry */ 116: #define TIME_OUT 10 /* time to wait for reply, in secs */ 117: 118: 119: struct sockaddr_in sin = {AF_INET}; 120: struct sockaddr_in dst = {AF_INET}; 121: struct servent *sp; 122: extern double ul_fixed_to_double(), s_fixed_to_double(); 123: extern int errno; 124: int set, verbose, force; 125: int debug; 126: extern int optind; 127: 128: main(argc, argv) 129: int argc; 130: char *argv[]; 131: { 132: struct hostent *hp; 133: struct in_addr clock_host; 134: struct l_fixedpt in_timestamp; 135: static struct ntpdata ntp_data; 136: struct ntpdata *pkt = &ntp_data; 137: struct timeval tp, timeout; 138: int host, n, retry, s; 139: fd_set readfds; 140: int dstlen = sizeof(dst); 141: double t1, t2, t3, t4, offset, delay; 142: char ref_clock[5]; 143: time_t net_time; 144: ref_clock[4] = '\0'; 145: 146: timeout.tv_sec = TIME_OUT; 147: timeout.tv_usec = 0; 148: retry = RETRY_COUNT; 149: 150: sp = getservbyname("ntp", "udp"); 151: if (sp == NULL) { 152: fprintf(stderr, "udp/ntp: service unknown; using default %d\n", 153: NTP_PORT); 154: dst.sin_port = htons(NTP_PORT); 155: } else 156: dst.sin_port = sp->s_port; 157: 158: dst.sin_family = AF_INET; 159: while ((n = getopt(argc, argv, "vsf")) != EOF) { 160: switch (n) { 161: case 'v': 162: verbose = 1; 163: break; 164: case 's': 165: set = 1; 166: break; 167: case 'f': 168: force = 1; 169: break; 170: } 171: } 172: for (host = optind; host < argc; ++host) { 173: long HostAddr; 174: 175: if (argv[host] == NULL) 176: continue; 177: 178: hp = NULL; 179: HostAddr = inet_addr(argv[host]); 180: dst.sin_addr.s_addr = (u_long) HostAddr; 181: if (HostAddr == -1) { 182: hp = gethostbyname(argv[host]); 183: if (hp == NULL) { 184: fprintf(stderr, "\nNo such host: %s\n", 185: argv[host]); 186: continue; 187: } 188: bcopy(hp->h_addr, (char *) &dst.sin_addr,hp->h_length); 189: } 190: 191: bzero((char *)pkt, sizeof(ntp_data)); 192: 193: pkt->status = NTPVERSION_1 | NO_WARNING | MODE_CLIENT; 194: pkt->stratum = UNSPECIFIED; 195: pkt->ppoll = 0; 196: 197: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 198: perror("ntp socket"); 199: exit(1); 200: } 201: 202: FD_ZERO(&readfds); 203: FD_SET(s, &readfds); /* since it's always modified on ret */ 204: 205: if (connect(s, (struct sockaddr *)&dst, dstlen)) { 206: perror("connect"); 207: exit(1); 208: } 209: 210: /* 211: * Needed to fill in the time stamp fields 212: */ 213: (void) gettimeofday(&tp, (struct timezone *) 0); 214: tstamp(&pkt->xmt, &tp); 215: 216: if (send(s, (char *) pkt, sizeof(ntp_data), 0) < 0) { 217: perror("send"); 218: exit(1); 219: } 220: 221: /* 222: * Wait for the reply by watching the file descriptor 223: */ 224: if ((n = select(FD_SETSIZE, (fd_set *) & readfds, (fd_set *) 0, 225: (fd_set *) 0, &timeout)) < 0) { 226: perror("ntp select"); 227: exit(1); 228: } 229: 230: if (n == 0) { 231: fprintf(stderr,"*Timeout*\n"); 232: if (--retry) 233: --host; 234: else { 235: fprintf(stderr,"Host %s is not responding\n", 236: argv[host]); 237: retry = RETRY_COUNT; 238: } 239: continue; 240: } 241: if ((recvfrom(s, (char *) pkt, sizeof(ntp_data), 0, 242: (struct sockaddr *) &sin, &dstlen)) < 0) { 243: perror("recvfrom"); 244: exit(1); 245: } 246: (void) gettimeofday(&tp, (struct timezone *) 0); 247: tstamp(&in_timestamp, &tp); 248: 249: close(s); 250: if (verbose) { 251: printf("Packet from: [%s]\n", inet_ntoa(sin.sin_addr)); 252: printf("Leap %d, version %d, mode %s, poll %d, precision %d stratum %d", 253: (pkt->status & LEAPMASK) >> 6, 254: (pkt->status & VERSIONMASK) >> 3, 255: modename[pkt->status & MODEMASK], 256: pkt->ppoll, pkt->precision, pkt->stratum); 257: switch (pkt->stratum) { 258: case 0: 259: case 1: 260: (void) strncpy(ref_clock, (char *) &pkt->refid, 4); 261: ref_clock[4] = '\0'; 262: printf(" (%s)\n", ref_clock); 263: break; 264: default: 265: clock_host.s_addr = (u_long) pkt->refid; 266: printf(" [%s]\n", inet_ntoa(clock_host)); 267: break; 268: } 269: printf("Synch Distance is %04x.%04x %f\n", 270: ntohs(pkt->distance.int_part), 271: ntohs(pkt->distance.fraction), 272: s_fixed_to_double(&pkt->distance)); 273: 274: printf("Synch Dispersion is %04x.%04x %f\n", 275: ntohs(pkt->dispersion.int_part), 276: ntohs(pkt->dispersion.fraction), 277: s_fixed_to_double(&pkt->dispersion)); 278: 279: net_time = ntohl(pkt->reftime.int_part) - JAN_1970; 280: printf("Reference Timestamp is %08lx.%08lx %s", 281: ntohl(pkt->reftime.int_part), 282: ntohl(pkt->reftime.fraction), 283: ctime(&net_time)); 284: 285: net_time = ntohl(pkt->org.int_part) - JAN_1970; 286: printf("Originate Timestamp is %08lx.%08lx %s", 287: ntohl(pkt->org.int_part), 288: ntohl(pkt->org.fraction), 289: ctime(&net_time)); 290: 291: net_time = ntohl(pkt->rec.int_part) - JAN_1970; 292: printf("Receive Timestamp is %08lx.%08lx %s", 293: ntohl(pkt->rec.int_part), 294: ntohl(pkt->rec.fraction), 295: ctime(&net_time)); 296: 297: net_time = ntohl(pkt->xmt.int_part) - JAN_1970; 298: printf("Transmit Timestamp is %08lx.%08lx %s", 299: ntohl(pkt->xmt.int_part), 300: ntohl(pkt->xmt.fraction), 301: ctime(&net_time)); 302: } 303: t1 = ul_fixed_to_double(&pkt->org); 304: t2 = ul_fixed_to_double(&pkt->rec); 305: t3 = ul_fixed_to_double(&pkt->xmt); 306: t4 = ul_fixed_to_double(&in_timestamp); 307: 308: net_time = ntohl(in_timestamp.int_part) - JAN_1970; 309: if (verbose) 310: printf("Input Timestamp is %08lx.%08lx %s", 311: ntohl(in_timestamp.int_part), 312: ntohl(in_timestamp.fraction), ctime(&net_time)); 313: 314: delay = (t4 - t1) - (t3 - t2); 315: offset = (t2 - t1) + (t3 - t4); 316: offset = offset / 2.0; 317: printf("%.20s: delay:%f offset:%f ", 318: hp ? hp->h_name : argv[host], 319: delay, offset); 320: net_time = ntohl(pkt->xmt.int_part) - JAN_1970 + delay; 321: fputs(ctime(&net_time), stdout); 322: (void)fflush(stdout); 323: 324: if (!set) 325: continue; 326: 327: if ((offset < 0 ? -offset : offset) > WAYTOOBIG && !force) { 328: fprintf(stderr, "Offset too large - use -f option to force clock set.\n"); 329: continue; 330: } 331: 332: if (pkt->status & LEAPMASK == ALARM) { 333: fprintf(stderr, "Can't set time from %s - unsynchronized\n", 334: argv[host]); 335: continue; 336: } 337: 338: /* set the clock */ 339: gettimeofday(&tp, (struct timezone *) 0); 340: offset += tp.tv_sec; 341: offset += tp.tv_usec / 1000000.0; 342: tp.tv_sec = offset; 343: tp.tv_usec = (offset - tp.tv_sec) * 1000000.0; 344: 345: if (settimeofday(&tp, (struct timezone *) 0)) { 346: perror("Can't set time (settimeofday)"); 347: } else 348: set = 0; 349: } /* end of for each host */ 350: exit(0); 351: } /* end of main */