home *** CD-ROM | disk | FTP | other *** search
- /* (C) Silvano Maffeis, maffeis@ifi.unizh.ch
- * University of Zurich, Switzerland 1992
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <errno.h>
- #include <signal.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <values.h>
- #include <malloc.h>
-
- #define DRIFT 0.00001 /* Drift of the hardware clock compared to "real time" */
- #define MIN_RT 1500 /* Shortest roundtrip measured in an ethernet lan */
- #define AVG_RT 2500 /* Average roundtrip measured in an ethernet lan */
- #define SUSPICIOUS 100000 /* Log time deviations > SUSPICIOUS microsec */
- #define VERSION "V1.0"
-
-
- extern getrtime();
-
-
- /* .......................globals.................................*/
- char **Argv;
- extern char *sys_errlist[];
- extern int errno;
- short synmon = 0;
- char *host;
- char *localHost;
- /* ...............................................................*/
-
- /* log an event
- */
- void LOG(str)
- char *str;
- {
- FILE *logF;
- struct tm *tm;
- struct timeval tv;
- char *date;
-
- if (gettimeofday(&tv, 0) < 0){
- fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
- LOG("panic: gettimeofday failed!");
- exit(1);
- };
-
- tm = localtime(&tv.tv_sec);
- date = (char*)malloc(25);
- strcpy(date, asctime(tm));
- date[24] = '\0'; /* overwrite '\n' */
-
- if(!synmon){
- logF = fopen(LOG_FILE, "a");
- if(logF == NULL){ free(date); return;}
-
- fprintf(logF, "%s: %s: %s\n", date, localHost, str);
- fclose(logF);
- free(date);
- }
- }
-
- /*
- * trap SIGINT:
- */
- #if defined(SYSV)
- void term_fcn(sig)
- #else
- term_fcn(sig)
- #endif SYSV
- int sig;
- {
- if(signal(sig, SIG_IGN) == SIG_ERR){
- fprintf(stderr, "%s: term_fcn %s\n", Argv[0], sys_errlist[errno]);
- exit(1);
- }
-
- LOG("Got a kill signal!");
-
- exit(1);
- }
-
- /*
- * handle signals:
- */
- int handle_sigs(){
- if(signal(SIGHUP, SIG_IGN) == SIG_ERR)
- return(0);
-
- if(signal(SIGINT, SIG_IGN) == SIG_ERR)
- return(0);
-
- if(signal(SIGQUIT, SIG_IGN) == SIG_ERR)
- return(0);
-
- if(signal(SIGTERM, term_fcn) == SIG_ERR)
- return(0);
-
- return(1);
- }
-
- /*
- * read time of day:
- */
- void time_get(seconds, usecs)
- long *seconds;
- long *usecs;
- {
- struct timeval tv;
-
- if (gettimeofday(&tv, 0) < 0){
- fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
- LOG("panic: gettimeofday failed!");
- exit(1);
- };
- *seconds = tv.tv_sec;
- *usecs = tv.tv_usec;
- }
-
- /*
- * calculate roundtrip
- * starttime must be <= endtime
- */
- long calc_roundtrip(start_s, start_u, end_s, end_u)
- long start_s;
- long start_u;
- long end_s;
- long end_u;
- {
-
- end_s -= start_s;
- if ((end_u -= start_u) < 0) {
- end_u += 1000000;
- --end_s;
- }
- return(end_u + end_s * 1000000);
- };
-
- /*
- * calculate delta
- * starttime can also be > endtime
- */
- long calc_delta(start_s, start_u, end_s, end_u)
- long start_s;
- long start_u;
- long end_s;
- long end_u;
- {
- if(start_s < end_s || ( start_s == end_s && start_u < end_u ))
- return calc_roundtrip(start_s, start_u, end_s, end_u);
-
- return 0-calc_roundtrip(end_s, end_u, start_s, start_u);
- };
-
- /*
- * set up connection to remote hosts
- */
- void init_connection(addrp)
- struct sockaddr_in *addrp;
- {
- struct servent *servent;
- long address;
- struct hostent *ph;
-
-
- if(isdigit(host[0])){
- if((address=inet_addr(host))==-1){
- fprintf(stderr, "%s: invalid inet number %s\n", Argv[0], host);
- exit(1);
- }
- addrp->sin_addr.s_addr=address;
- addrp->sin_family=AF_INET;
- }
- else{
- addrp->sin_family = AF_INET;
- if((ph = gethostbyname(host)) == 0){
- fprintf(stderr, "%s: unknown host %s\n", Argv[0], host);
- exit(1);
- }
- bcopy(ph->h_addr, &addrp->sin_addr, ph->h_length);
- }
-
- #ifndef PORT
- servent = getservbyname("utime", "udp");
- if(servent == NULL){
- fprintf(stderr, "%s: getservbyname: %s\n", Argv[0], sys_errlist[errno]);
- exit(1);
- };
-
- addrp->sin_port = htons(servent->s_port);
- #else
- addrp->sin_port = htons(PORT);
- #endif PORT
-
- };
-
- /* read parameters from config file
- */
- void loadParams(file, sleept)
- char *file;
- int *sleept;
- {
- FILE *conf;
- static unsigned char is_loaded = 0;
-
- conf = fopen(file, "r");
- if(conf == NULL){
- if(is_loaded) return;
-
- fprintf(stderr, "%s: cannot open %s: %s\n", Argv[0], file,
- sys_errlist[errno]);
- exit(1);
- };
- is_loaded = 1;
-
- if(fscanf(conf, "%s %d\n", host, sleept) != 2){
- fprintf(stderr, "%s: syntax error in %s\n", Argv[0], file);
- exit(1);
- };
- fclose(conf);
- }
-
- short rt_is_lower(rt, now_sec, now_usec)
- double rt;
- double now_sec;
- double now_usec;
- {
- static double llast = -1.0;
- static double shortest = MAXDOUBLE;
- double elapsed, tmp;
-
- if(llast==-1.0) llast = now_sec * 1000000.0 + now_usec;
-
- elapsed = (now_sec * 1000000.0 + now_usec) - llast;
-
- if(synmon){
- printf("now = %0.f, %0.f\n", now_sec, now_usec);
- printf("last = %0.f\n", llast);
- if(shortest != MAXDOUBLE)
- printf("shortest roundtrip so far = %.0f usec\n", shortest);
- printf("last adjustement = %.0f usec ago\n", elapsed);
- };
-
- tmp = now_sec*1000000.0 + now_usec;
-
- if(rt < shortest + 2*DRIFT * elapsed){
- shortest = rt;
- llast = tmp;
- return 1;
- }
-
- return 0;
- }
-
- /******************************************************************************/
- main(argc, argv)
- int argc;
- char **argv;
- {
- struct sockaddr_in addr;
- struct timeval time, ltime, ntime;
- int ret;
- long start_sec, start_usec, end_sec, end_usec, rt, delta;
- int sleept;
- char buf[64], str[32];
-
- Argv = argv;
-
- if(argc != 3 && argc != 1){
- fprintf(stderr, "usage: %s remotehost timeinterval\n", Argv[0]);
- exit(1);
- };
-
- if( argc == 1 ){
- host = (char*)malloc(64);
- loadParams(CONF, &sleept);
- }
- else{
- if(sscanf(Argv[2], "%d", &sleept) != 1){
- fprintf(stderr, "%s: parameter 2 must be an integer value\n", Argv[0]);
- exit(1);
- };
- host = Argv[1];
- }
-
- localHost = (char*)malloc(64);
- gethostname(localHost, 64);
-
- if(strcmp(argv[0], "synmon") == 0) synmon = 1;
- init_connection(&addr, host);
-
- sprintf(str, "synclockd %s started", VERSION);
- LOG(str);
-
- if(synmon){
- printf("remote host = %s\n", host);
- printf("time interval = %d\n", sleept);
- }
- else
- handle_sigs();
-
- while(1){
- if(synmon)
- printf("\npolling %s:\n", host);
-
- time_get(&start_sec, &start_usec);
- ret = getrtime(&addr, &time);
- time_get(&end_sec, &end_usec);
-
- if(ret != 0){ /* rtimel timed stderr. Retry later */
- if(synmon)
- fprintf(stderr, "%s: connection to %s timed out\n", Argv[0], host);
- else
- LOG("connection to time server timed out");
- sleep(sleept);
- continue;
- }
-
- ret = gettimeofday(<ime, (struct timezone*)0);
- if(ret != 0){
- fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
- LOG("panic: gettimeofday failed!");
- exit(1);
- }
-
- rt = calc_roundtrip(start_sec, start_usec, end_sec, end_usec);
-
- /*
- * since gettimeofday()'s _real_ exactness is around 1/60 second,
- * most rountripdelays in a LAN will become 0 if we rely on
- * gettimeofday().
- * Too small values ( < MIN_RT ) are corrected to AVG_RT. Both values
- * derive from measurements using an exact timer we undertook
- * in a Ethernet LAN.
- */
- if(rt < MIN_RT) rt = AVG_RT;
-
- /*
- * Next we look if the actual roundtrip is smaller than the corrected,
- * shortest roundtrip so far:
- * rt < rt_min + 2 * (1+DRIFT) * elapsed_time.
- * With rt being the actual roundtrip, rt_min the shortest roundtrip
- * encountered so far and the rest a parameter taking into
- * account the maximal drift of two clocks.
- */
- if( rt_is_lower((double)rt, (double)start_sec, (double)start_usec, synmon) ){
- if(synmon){
- printf("roundtrip is lower : %ld usec\n", rt);
- printf("remote time: %ld sec, %ld usec\n", time.tv_sec, time.tv_usec);
- printf("local time : %ld sec, %ld usec\n", ltime.tv_sec, ltime.tv_usec);
- }
-
- /* compute time-delta between remote and local:
- * roundtrip/2 + remote - local .
- * If delta is positive, then speed up clock, else slow down.
- */
- delta = rt/2 +
- calc_delta(ltime.tv_sec, ltime.tv_usec, time.tv_sec, time.tv_usec);
-
- if(delta != 0){
-
- ntime.tv_sec = delta/1000000;
- ntime.tv_usec = delta - ntime.tv_sec * 1000000;
-
- if(!synmon){
- ret = adjtime(&ntime, 0);
- if(ret != 0){
- fprintf(stderr, "%s: adjtime: %s\n", Argv[0], sys_errlist[errno]);
- LOG("panic: adjtime failed");
- exit(1);
- }
- }
-
- /* Look if the difference between local and remote clock
- * is "suspiciously" high. If so, log it.
- */
- rt = calc_delta(time.tv_sec, time.tv_usec, ltime.tv_sec,
- ltime.tv_usec);
-
- if(abs(rt) > SUSPICIOUS){
- sprintf(buf, "suspicious time difference: %ld", rt);
- LOG(buf);
- }
- }
-
- if(synmon){
- printf("advancing local clock by %ld sec, %ld usec\n",
- ntime.tv_sec, ntime.tv_usec);
- }
- }
- else
- if(synmon)
- printf("roundtrip is *not* lower : %d usec\n", rt);
-
- sleep(sleept);
-
- /* allows to configure synclockd at runtime:
- */
- if(argc == 1)
- loadParams(CONF, host, &sleept);
- }
- }
-