1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)measure.c 2.4 (Berkeley) 5/28/86"; 9: #endif not lint 10: 11: #include "globals.h" 12: #include <protocols/timed.h> 13: #include <netinet/in_systm.h> 14: #include <netinet/ip.h> 15: #include <netinet/ip_icmp.h> 16: 17: #define BIASP 43199999 18: #define BIASN -43200000 19: #define MODULO 86400000 20: #define PROCESSING_TIME 5 /* ms. to reduce error in measurement */ 21: 22: #define PACKET_IN 1024 23: 24: extern int id; 25: int measure_delta; 26: extern int sock_raw; 27: static n_short seqno = 0; 28: 29: /* 30: * Measures the differences between machines' clocks using 31: * ICMP timestamp messages. 32: */ 33: 34: measure(wait, addr) 35: struct timeval *wait; 36: struct sockaddr_in *addr; 37: { 38: int length; 39: int status; 40: int msgcount, trials; 41: int cc, count; 42: fd_set ready; 43: long sendtime, recvtime, histime; 44: long min1, min2, diff; 45: register long delta1, delta2; 46: struct timeval tv1, tout; 47: u_char packet[PACKET_IN], opacket[64]; 48: register struct icmp *icp = (struct icmp *) packet; 49: register struct icmp *oicp = (struct icmp *) opacket; 50: struct ip *ip = (struct ip *) packet; 51: 52: min1 = min2 = 0x7fffffff; 53: status = HOSTDOWN; 54: measure_delta = HOSTDOWN; 55: 56: /* empties the icmp input queue */ 57: FD_ZERO(&ready); 58: empty: 59: tout.tv_sec = tout.tv_usec = 0; 60: FD_SET(sock_raw, &ready); 61: if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 62: length = sizeof(struct sockaddr_in); 63: cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 64: (struct sockaddr_in *)NULL, &length); 65: if (cc < 0) 66: return(-1); 67: goto empty; 68: } 69: 70: /* 71: * To measure the difference, select MSGS messages whose round-trip 72: * time is smaller than RANGE if ckrange is 1, otherwise simply 73: * select MSGS messages regardless of round-trip transmission time. 74: * Choose the smallest transmission time in each of the two directions. 75: * Use these two latter quantities to compute the delta between 76: * the two clocks. 77: */ 78: 79: length = sizeof(struct sockaddr_in); 80: oicp->icmp_type = ICMP_TSTAMP; 81: oicp->icmp_code = 0; 82: oicp->icmp_cksum = 0; 83: oicp->icmp_id = id; 84: oicp->icmp_rtime = 0; 85: oicp->icmp_ttime = 0; 86: FD_ZERO(&ready); 87: msgcount = 0; 88: for (trials = 0; msgcount < MSGS && trials < TRIALS; ++trials) { 89: oicp->icmp_seq = ++seqno; 90: oicp->icmp_cksum = 0; 91: 92: tout.tv_sec = wait->tv_sec; 93: tout.tv_usec = wait->tv_usec; 94: 95: (void)gettimeofday (&tv1, (struct timezone *)0); 96: sendtime = oicp->icmp_otime = (tv1.tv_sec % (24*60*60)) * 1000 97: + tv1.tv_usec / 1000; 98: oicp->icmp_cksum = in_cksum((u_short *)oicp, sizeof(*oicp)); 99: 100: count = sendto(sock_raw, (char *)opacket, sizeof(*oicp), 0, 101: addr, sizeof(struct sockaddr_in)); 102: if (count < 0) { 103: status = UNREACHABLE; 104: return(-1); 105: } 106: for (;;) { 107: FD_SET(sock_raw, &ready); 108: if ((count = select(FD_SETSIZE, &ready, (fd_set *)0, 109: (fd_set *)0, &tout)) <= 0) 110: break; 111: cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 112: (struct sockaddr_in *)NULL, &length); 113: (void)gettimeofday(&tv1, (struct timezone *)0); 114: if (cc < 0) 115: return(-1); 116: icp = (struct icmp *)(packet + (ip->ip_hl << 2)); 117: if((icp->icmp_type == ICMP_TSTAMPREPLY) && 118: icp->icmp_id == id && icp->icmp_seq == seqno) 119: break; 120: } 121: if (count <= 0) 122: continue; /* resend */ 123: recvtime = (tv1.tv_sec % (24*60*60)) * 1000 + 124: tv1.tv_usec / 1000; 125: diff = recvtime - sendtime; 126: /* 127: * diff can be less than 0 aroud midnight 128: */ 129: if (diff < 0) 130: continue; 131: msgcount++; 132: histime = ntohl((u_long)icp->icmp_rtime); 133: /* 134: * a hosts using a time format different from 135: * ms. since midnight UT (as per RFC792) should 136: * set the high order bit of the 32-bit time 137: * value it transmits. 138: */ 139: if ((histime & 0x80000000) != 0) { 140: status = NONSTDTIME; 141: break; 142: } 143: status = GOOD; 144: delta1 = histime - sendtime; 145: /* 146: * Handles wrap-around to avoid that around 147: * midnight small time differences appear 148: * enormous. However, the two machine's clocks 149: * must be within 12 hours from each other. 150: */ 151: if (delta1 < BIASN) 152: delta1 += MODULO; 153: else if (delta1 > BIASP) 154: delta1 -= MODULO; 155: delta2 = recvtime - histime; 156: if (delta2 < BIASN) 157: delta2 += MODULO; 158: else if (delta2 > BIASP) 159: delta2 -= MODULO; 160: if (delta1 < min1) 161: min1 = delta1; 162: if (delta2 < min2) 163: min2 = delta2; 164: if (diff < RANGE) { 165: min1 = delta1; 166: min2 = delta2; 167: break; 168: } 169: } 170: 171: /* 172: * If no answer is received for TRIALS consecutive times, 173: * the machine is assumed to be down 174: */ 175: if (status == GOOD) { 176: measure_delta = (min1 - min2)/2 + PROCESSING_TIME; 177: } 178: return(status); 179: }