home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / alt / sources / 2845 < prev    next >
Encoding:
Text File  |  1992-12-22  |  24.4 KB  |  930 lines

  1. Newsgroups: alt.sources
  2. Path: sparky!uunet!zaphod.mps.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!agate!spool.mu.edu!yale.edu!ira.uka.de!chx400!josef!maffeis
  3. From: maffeis@ifi.unizh.ch (Silvano Maffeis)
  4. Subject: synclockd: Clock synchronization daemons
  5. Message-ID: <1992Dec22.125836.22960@ifi.unizh.ch>
  6. Organization: University of Zurich, Department of Computer Science
  7. Date: Tue, 22 Dec 92 12:58:36 GMT
  8. Lines: 920
  9.  
  10.  
  11. Submitted-by: maffeis@ifi.unizh.ch (silvano maffeis)
  12. Archive-name: synclockd.shar
  13.  
  14.  
  15. Here are two simple and pretty accurate daemons for performing
  16. clock synchronization in a LAN. Several workstations can be 
  17. synchronized with a central time server host for example. 
  18. The daemons work under SunOS 4, Ultrix, SYSV (Amiga), IRIX 4.0.X,
  19. AIX 3.x and possibly on other UNIXes as well.
  20.  
  21. The daemons work independently of any daytime or time inetd
  22. service. Clocks are advanced or retarded using adjtime(2),
  23. which guarantees always monotonically increasing timevalues.
  24. The implemented synchronization mechanism is an adaptation
  25. of the Cristian's algorithm.
  26.  
  27. ----------------- cut here -----------------------------------------------
  28. #! /bin/sh
  29. # This is a shell archive.  Remove anything before this line, then unpack
  30. # it by saving it into a file and typing "sh file".  To overwrite existing
  31. # files, type "sh file -c".  You can also feed this as standard input via
  32. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  33. # will see the following message at the end:
  34. #        "End of shell archive."
  35. # Contents:  Makefile README getrtime.c synclockd.c synclockd.conf
  36. #   synservd.c
  37. # Wrapped by maffeis@sebastian on Wed Dec 16 15:26:19 1992
  38. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  39. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  40.   echo shar: Will not clobber existing file \"'Makefile'\"
  41. else
  42. echo shar: Extracting \"'Makefile'\" \(1744 characters\)
  43. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  44. X# This is the Makefile for building the clock synchronisation daemons.
  45. X# Currently, we support SUNOS, Ultrix, Amiga Unix (SYSVR4) and AIX.
  46. X# This software should also work on other Unix flavors
  47. X# without or with only small adaptions.
  48. X#
  49. X# Author: Silvano Maffeis, maffeis@ifi.unizh.ch 1992
  50. X
  51. X
  52. X#CC=gcc
  53. XCC=cc
  54. X
  55. X# Some defaults
  56. XINSTALL = install
  57. X
  58. X# no extra flags necessary for SunOS 4
  59. X
  60. X# uncomment this for SYSV (Amiga)
  61. X#LDLIBS=-lbsd43    
  62. X#STD_DEFINES = -DSYSV
  63. X
  64. X# uncomment this for IRIX 4.0.X (SiliconGraphics)
  65. X#LDLIBS=-lsun
  66. X#STD_DEFINES = -DSYSV
  67. X#CCOPTIONS = -cckr
  68. X#INSTALL = /usr/bin/X11/bsdinst.sh
  69. X
  70. X# uncomment this for Ultrix
  71. X#STD_DEFINES = -DSYSV
  72. X
  73. X#uncomment this for AIX
  74. X#LDLIBS=-lbsd
  75. X#STD_DEFINES = -DSYSV
  76. X
  77. X# where binaries go:
  78. XBINDIR=/usr/local/etc
  79. X
  80. X# path of the config file:
  81. XCONF_FILE=/usr/local/etc/synclockd.conf
  82. X
  83. X# path of the log file:
  84. XLOG_FILE=/usr/local/etc/synclockd.log
  85. X
  86. X# add -DPORT=number to 'DEFINES=' below to hardcode a udp port number 
  87. X# and avoid using /etc/services
  88. X
  89. XDEFINES=-DCONF=\"$(CONF_FILE)\" -DLOG_FILE=\"$(LOG_FILE)\" #-DPORT=9000
  90. XCDEBUGFLAGS = -O
  91. XCCLDFLAGS=
  92. X
  93. X# ------------You probably need not edit below this line ----------------------
  94. X
  95. XCFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(DEFINES) $(STD_DEFINES)
  96. X
  97. Xall:        synclockd synservd
  98. X
  99. Xsynclockd:    synclockd.o getrtime.o
  100. X        $(CC) $(CCLDFLAGS) -o synclockd synclockd.o getrtime.o $(LDLIBS)
  101. X        rm -f synmon
  102. X        ln -s synclockd synmon
  103. X
  104. Xsynservd:    synservd.o
  105. X        $(CC) $(CCLDFLAGS) -o synservd synservd.o $(LDLIBS)
  106. X
  107. X
  108. Xinstall:    synclockd
  109. X        $(INSTALL) -m 1755 -s synclockd $(BINDIR)
  110. X        $(INSTALL) -m 1755 -s synservd $(BINDIR)
  111. X        rm -f $(BINDIR)/synmon
  112. X        ln -s $(BINDIR)/synclockd $(BINDIR)/synmon
  113. X        
  114. X
  115. Xclean:    
  116. X        rm -f core *.o *% *~
  117. X
  118. Xrealclean:    clean
  119. X        rm -f synclockd synservd cs synmon
  120. END_OF_FILE
  121. if test 1744 -ne `wc -c <'Makefile'`; then
  122.     echo shar: \"'Makefile'\" unpacked with wrong size!
  123. fi
  124. # end of 'Makefile'
  125. fi
  126. if test -f 'README' -a "${1}" != "-c" ; then 
  127.   echo shar: Will not clobber existing file \"'README'\"
  128. else
  129. echo shar: Extracting \"'README'\" \(4392 characters\)
  130. sed "s/^X//" >'README' <<'END_OF_FILE'
  131. XAuthor
  132. X======
  133. XSilvano Maffeis, maffeis@ifi.unizh.ch, Oct 1992
  134. X
  135. XThis directory contains two daemons: synclockd, a simple but pretty accurate 
  136. Xclock synchronization daemon and synservd, the server-daemon for
  137. Xsynclockd. I think they work sufficiently exact to synchronize many 
  138. Xclient clocks in a LAN. 
  139. X
  140. Xsynclockd
  141. X=========
  142. Xsynopsis: synclockd [serverhost timeinterval]
  143. Xinvoked without arguments, synclockd reads its parameters from
  144. X/usr/local/etc/synservd.conf 
  145. X(or whatever path you specified in the Makefile)
  146. X
  147. XThe underlying time-synchronization method is based upon the
  148. Xassumption that the roundtrip delay of a UDP data packet in a LAN is made
  149. Xup by two almost identical parts. 
  150. X
  151. XThis is known as the basic Cristian's algorithm. One enhancement we make:
  152. XWhen the measured roundtrip delay is higher than the smallest one
  153. Xencountered so far, we discard the measured value and don't alterate 
  154. Xthe local clock.
  155. XThe smallest roundtrip value is corrected using a factor containing
  156. Xthe maximal amount two clocks can drift away from each other,
  157. Xwhich is 2*DRIFT. (If we would not make this correction, then no more 
  158. Xclock adjustments would be performed when the minimal roundtrip delay is
  159. Xreached.)
  160. X
  161. XSynclockd adjusts the local clock using adjtime(), hence
  162. Xguaranteeing an always monotonically increasing local time. 
  163. Xadjtime() just speeds up, resp. slows down the local
  164. Xclock by a few percents until the time value computed by our algorithm
  165. Xis reached. Therefore it initially can take some time till 
  166. Xclocks are synchronized.
  167. X
  168. Xsynservd
  169. X========
  170. XSince services like time, daytime, rdate(), rtime() are not accurate
  171. Xenough (these services usually provide a granularity of one second), the time 
  172. Xserver daemon synservd is also provided.
  173. Xsynservd listens on a udp socket for incoming synclockd requests and 
  174. Xreturns the local time as obtained from gettimeofday(2).
  175. X
  176. XA possible way for synchronizing several clients is to choose
  177. Xone host in the LAN known for his high availability and exact
  178. Xlocal time clock as time-server. A synclockd is started on every client.
  179. XA synservd is started only on the time-server host. (The time-server
  180. Xitself needs no synclockd in this case).
  181. X
  182. XMultiple LANs can be synchronized by realizing a hierarchy of
  183. Xtime-servers and time-clients.
  184. X
  185. Xsynmon
  186. X======
  187. Xsynmon is a simple monitor which helps in finding out how exact
  188. Xa client clock is synchronized with the server.
  189. X
  190. Xsynmon servername 5
  191. X
  192. XDisplays information about the synchronization process every 5
  193. Xseconds.
  194. X
  195. X
  196. XEXACTNESS
  197. X=========
  198. XThe maximal accurateness af the synchronization depends on the true
  199. Xexactness of gettimeofday(). For SPARCS running sunos 4, the logical 
  200. Xtick value is
  201. X1/100 of a second, and therefore you cannot believe the microsecond values
  202. Xreturned by gettimeofday(). 
  203. XThus, the difference of local to remote can be up to
  204. X1/99.999 seconds even when the daemons would provide for a 100%
  205. Xexact synchronization, which is impossible to achieve anyway.
  206. X
  207. X
  208. XINSTALLATION
  209. X============
  210. XInspect the Makefile and make changes if needed.
  211. XCompile the daemons by typing ``make''.
  212. X
  213. XYou then need an entry for the synchronization service in 
  214. X/etc/services:
  215. X
  216. Xutime           8500/udp                        # time synch daemon
  217. X
  218. Xsynclockd must run under root privileges since you must be superuser to
  219. Xuse adjtime(). The best way to start it
  220. Xis from the /etc/rc.local file of the client using something like:
  221. X
  222. X# synchronize local clock with host.foo.bar.edu every hour:
  223. X/usr/etc/synclockd host.foo.bar.edu 3600 &
  224. X
  225. Xor just
  226. X/usr/etc/synclockd &
  227. X
  228. XIn the latter case, the two parameters are read from a configuration file.
  229. X(something like /usr/local/etc/synclockd.conf. This filename is
  230. X specified in the Makefile). 
  231. Xhost.foo.bar.edu is the name of the time-server on which synservd runs.
  232. X
  233. X
  234. XSUGGESTED READING
  235. X=================
  236. X
  237. XA.S. Tanenbaum, "Modern Operating Systems", Chapter 11.1
  238. XD. Mills, Net Time Protocol (ntp), Articles on louie.udel.edu: pub/ntp/doc
  239. X
  240. X
  241. XBUGS:
  242. X=====
  243. X
  244. XThe daemons are used since a while over here to synchronize around
  245. X30 clients (Sparcs, Silicon Graphics, RS6000, DecStation,...) in a LAN. 
  246. XA client clock normally differs by only
  247. Xa few 0.001 sec from the server clock. We work with a synchronization
  248. Xinterval of 1800 sec.
  249. X
  250. XNevertheless, some bugs surely exist. If you find some, please report them.
  251. XPlease inform me of useful enhancements you make to the daemons.
  252. X
  253. XSilvano Maffeis, maffeis@ifi.unizh.ch
  254. X
  255. END_OF_FILE
  256. if test 4392 -ne `wc -c <'README'`; then
  257.     echo shar: \"'README'\" unpacked with wrong size!
  258. fi
  259. # end of 'README'
  260. fi
  261. if test -f 'getrtime.c' -a "${1}" != "-c" ; then 
  262.   echo shar: Will not clobber existing file \"'getrtime.c'\"
  263. else
  264. echo shar: Extracting \"'getrtime.c'\" \(1236 characters\)
  265. sed "s/^X//" >'getrtime.c' <<'END_OF_FILE'
  266. X/* (C) Silvano Maffeis, maffeis@ifi.unizh.ch
  267. X * University of Zurich, Switzerland 1992
  268. X *
  269. X * getrtime.c: read time from remote host using udp    
  270. X */
  271. X
  272. X#include <stdio.h>
  273. X#include <sys/time.h>
  274. X#include <sys/types.h>
  275. X#include <sys/socket.h>
  276. X#include <sys/errno.h>
  277. X#include <netinet/in.h>
  278. X
  279. Xextern errno;
  280. X
  281. Xvoid sclose(s)
  282. X     int s;
  283. X{
  284. X  int save;
  285. X  
  286. X  save = errno;
  287. X  (void) close(s);
  288. X  errno = save;
  289. X}
  290. X
  291. Xgetrtime(addrp, timep)
  292. X     struct sockaddr_in *addrp;
  293. X     struct timeval *timep;
  294. X{
  295. X  int s;
  296. X  int res;
  297. X  char thetime[2*sizeof(long)];
  298. X  struct timeval *rtime = (struct timeval *)thetime;
  299. X  struct sockaddr_in from;
  300. X  int fromlen;
  301. X
  302. X  s = socket(AF_INET, SOCK_DGRAM, 0);
  303. X  if (s < 0) {
  304. X    return(-1);
  305. X  }
  306. X  addrp->sin_family = AF_INET;
  307. X  res = sendto(s, (char *)thetime, 2*sizeof(long), 0, 
  308. X           (struct sockaddr *)addrp, sizeof(*addrp));
  309. X  if (res < 0) {
  310. X    sclose(s);
  311. X    return(-1);    
  312. X  }
  313. X  fromlen = sizeof(from);
  314. X  res = recvfrom(s, (char *)thetime, 2*sizeof(long), 0, 
  315. X         (struct sockaddr *)&from, &fromlen);
  316. X  sclose(s);
  317. X  if (res < 0) {
  318. X    return(-1);    
  319. X  }
  320. X  if (res != sizeof(thetime)) {
  321. X    errno = EIO;
  322. X    return(-1);    
  323. X  }
  324. X  timep->tv_sec  = ntohl(rtime->tv_sec);
  325. X  timep->tv_usec = ntohl(rtime->tv_usec);
  326. X  return(0);
  327. X}
  328. X
  329. END_OF_FILE
  330. if test 1236 -ne `wc -c <'getrtime.c'`; then
  331.     echo shar: \"'getrtime.c'\" unpacked with wrong size!
  332. fi
  333. # end of 'getrtime.c'
  334. fi
  335. if test -f 'synclockd.c' -a "${1}" != "-c" ; then 
  336.   echo shar: Will not clobber existing file \"'synclockd.c'\"
  337. else
  338. echo shar: Extracting \"'synclockd.c'\" \(9596 characters\)
  339. sed "s/^X//" >'synclockd.c' <<'END_OF_FILE'
  340. X/* (C) Silvano Maffeis, maffeis@ifi.unizh.ch             
  341. X * University of Zurich, Switzerland 1992            
  342. X */
  343. X
  344. X#include <stdio.h>
  345. X#include <string.h>
  346. X#include <sys/types.h>
  347. X#include <sys/time.h>
  348. X#include <sys/socket.h>
  349. X#include <errno.h>
  350. X#include <signal.h>
  351. X#include <netinet/in.h>
  352. X#include <netdb.h>
  353. X#include <values.h>
  354. X#include <malloc.h>
  355. X
  356. X#define DRIFT      0.00001    /* Drift of the hardware clock compared to "real time" */
  357. X#define MIN_RT       1500       /* Shortest roundtrip measured in an ethernet lan      */
  358. X#define AVG_RT       2500       /* Average roundtrip measured in an ethernet lan       */
  359. X#define SUSPICIOUS 100000     /* Log time deviations > SUSPICIOUS microsec           */
  360. X#define VERSION    "V1.0" 
  361. X
  362. X
  363. Xextern getrtime();
  364. X
  365. X
  366. X/* .......................globals.................................*/
  367. Xchar **Argv;
  368. Xextern char *sys_errlist[];
  369. Xextern int errno;
  370. Xshort synmon = 0;
  371. Xchar *host;
  372. Xchar *localHost;
  373. X/* ...............................................................*/
  374. X
  375. X/* log an event
  376. X */
  377. Xvoid LOG(str)
  378. X     char *str;
  379. X{
  380. X  FILE *logF;
  381. X  struct tm *tm; 
  382. X  struct timeval tv;
  383. X  char *date;
  384. X  
  385. X  if (gettimeofday(&tv, 0) < 0){
  386. X    fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);    
  387. X    LOG("panic: gettimeofday failed!");
  388. X    exit(1);       
  389. X  };
  390. X  
  391. X  tm = localtime(&tv.tv_sec);
  392. X  date = (char*)malloc(25);
  393. X  strcpy(date, asctime(tm));
  394. X  date[24] = '\0';   /* overwrite '\n' */
  395. X  
  396. X  if(!synmon){
  397. X    logF = fopen(LOG_FILE, "a");
  398. X    if(logF == NULL){ free(date); return;}
  399. X    
  400. X    fprintf(logF, "%s: %s: %s\n", date, localHost, str); 
  401. X    fclose(logF);
  402. X    free(date);
  403. X  }
  404. X}
  405. X
  406. X/* 
  407. X * trap SIGINT:
  408. X */
  409. X#if defined(SYSV)
  410. Xvoid term_fcn(sig)
  411. X#else
  412. X     term_fcn(sig)
  413. X#endif SYSV
  414. X     int sig;
  415. X{
  416. X  if(signal(sig, SIG_IGN) == SIG_ERR){
  417. X    fprintf(stderr, "%s: term_fcn %s\n", Argv[0], sys_errlist[errno]);
  418. X    exit(1);
  419. X  }
  420. X  
  421. X  LOG("Got a kill signal!");
  422. X  
  423. X  exit(1);
  424. X}
  425. X
  426. X/*
  427. X * handle signals:
  428. X */
  429. Xint handle_sigs(){
  430. X  if(signal(SIGHUP, SIG_IGN) == SIG_ERR)
  431. X    return(0);
  432. X  
  433. X  if(signal(SIGINT, SIG_IGN) == SIG_ERR)
  434. X    return(0);
  435. X  
  436. X  if(signal(SIGQUIT, SIG_IGN) == SIG_ERR)
  437. X    return(0);
  438. X  
  439. X  if(signal(SIGTERM, term_fcn) == SIG_ERR)
  440. X    return(0);
  441. X  
  442. X  return(1);
  443. X}
  444. X
  445. X/*
  446. X * read time of day:
  447. X */
  448. Xvoid  time_get(seconds, usecs)
  449. X     long *seconds;
  450. X     long *usecs;
  451. X{
  452. X  struct timeval tv;
  453. X  
  454. X  if (gettimeofday(&tv, 0) < 0){
  455. X    fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
  456. X    LOG("panic: gettimeofday failed!");
  457. X    exit(1);
  458. X  };
  459. X  *seconds = tv.tv_sec;
  460. X  *usecs   = tv.tv_usec;
  461. X}
  462. X
  463. X/*
  464. X * calculate roundtrip
  465. X * starttime must be <= endtime
  466. X */ 
  467. Xlong calc_roundtrip(start_s, start_u, end_s, end_u)
  468. X     long start_s;
  469. X     long start_u;
  470. X     long end_s;
  471. X     long end_u;
  472. X{
  473. X  
  474. X  end_s -= start_s;
  475. X  if ((end_u -= start_u) < 0) {
  476. X    end_u += 1000000;
  477. X    --end_s;
  478. X  }
  479. X  return(end_u + end_s * 1000000);
  480. X};
  481. X
  482. X/*
  483. X * calculate delta
  484. X * starttime can also be > endtime
  485. X */ 
  486. Xlong calc_delta(start_s, start_u, end_s, end_u)
  487. X     long start_s;
  488. X     long start_u;
  489. X     long end_s;
  490. X     long end_u;
  491. X{
  492. X  if(start_s < end_s || ( start_s == end_s && start_u < end_u ))
  493. X    return calc_roundtrip(start_s, start_u, end_s, end_u);
  494. X  
  495. X  return 0-calc_roundtrip(end_s, end_u, start_s, start_u);
  496. X};
  497. X
  498. X/*
  499. X * set up connection to remote hosts
  500. X */
  501. Xvoid init_connection(addrp)
  502. X     struct sockaddr_in *addrp;
  503. X{
  504. X  struct servent *servent;
  505. X  long address;
  506. X  struct hostent *ph;
  507. X  
  508. X  
  509. X  if(isdigit(host[0])){
  510. X    if((address=inet_addr(host))==-1){
  511. X      fprintf(stderr, "%s: invalid inet number %s\n", Argv[0], host);
  512. X      exit(1);
  513. X    }
  514. X    addrp->sin_addr.s_addr=address;
  515. X    addrp->sin_family=AF_INET;
  516. X  }
  517. X  else{
  518. X    addrp->sin_family = AF_INET;
  519. X    if((ph = gethostbyname(host)) == 0){
  520. X      fprintf(stderr, "%s: unknown host %s\n", Argv[0], host);
  521. X      exit(1);
  522. X    }
  523. X    bcopy(ph->h_addr, &addrp->sin_addr, ph->h_length);
  524. X  }
  525. X  
  526. X#ifndef PORT
  527. X  servent = getservbyname("utime", "udp");
  528. X  if(servent == NULL){
  529. X    fprintf(stderr, "%s: getservbyname: %s\n", Argv[0], sys_errlist[errno]);
  530. X    exit(1);
  531. X  };
  532. X  
  533. X  addrp->sin_port = htons(servent->s_port);
  534. X#else
  535. X  addrp->sin_port = htons(PORT);
  536. X#endif PORT
  537. X  
  538. X};
  539. X
  540. X/* read parameters from config file
  541. X */
  542. Xvoid loadParams(file, sleept)
  543. X     char *file;
  544. X     int *sleept;
  545. X{
  546. X  FILE *conf;
  547. X  static unsigned char is_loaded = 0;
  548. X  
  549. X  conf = fopen(file, "r");
  550. X  if(conf == NULL){
  551. X    if(is_loaded) return;
  552. X    
  553. X    fprintf(stderr, "%s: cannot open %s: %s\n", Argv[0], file,
  554. X        sys_errlist[errno]);
  555. X    exit(1);
  556. X  };
  557. X  is_loaded = 1;
  558. X  
  559. X  if(fscanf(conf, "%s %d\n", host, sleept) != 2){
  560. X    fprintf(stderr, "%s: syntax error in %s\n", Argv[0], file);
  561. X    exit(1);
  562. X  };
  563. X  fclose(conf); 
  564. X}
  565. X
  566. Xshort rt_is_lower(rt, now_sec, now_usec)
  567. X     double rt;
  568. X     double now_sec;
  569. X     double now_usec;
  570. X{
  571. X  static double llast = -1.0;
  572. X  static double shortest = MAXDOUBLE;
  573. X  double elapsed, tmp;
  574. X  
  575. X  if(llast==-1.0) llast = now_sec * 1000000.0 + now_usec;
  576. X  
  577. X  elapsed = (now_sec * 1000000.0 + now_usec) - llast;
  578. X  
  579. X  if(synmon){
  580. X    printf("now = %0.f, %0.f\n", now_sec, now_usec);
  581. X    printf("last = %0.f\n", llast);
  582. X    if(shortest != MAXDOUBLE)
  583. X      printf("shortest roundtrip so far = %.0f usec\n", shortest);
  584. X    printf("last adjustement          = %.0f usec ago\n", elapsed);
  585. X  };
  586. X  
  587. X  tmp = now_sec*1000000.0 + now_usec;
  588. X  
  589. X  if(rt < shortest + 2*DRIFT * elapsed){
  590. X    shortest = rt;
  591. X    llast = tmp;
  592. X    return 1;
  593. X  }
  594. X  
  595. X  return 0;
  596. X}
  597. X
  598. X/******************************************************************************/
  599. Xmain(argc, argv)
  600. X     int argc;
  601. X     char **argv;
  602. X{
  603. X  struct sockaddr_in addr;
  604. X  struct timeval time, ltime, ntime;
  605. X  int ret;
  606. X  long start_sec, start_usec, end_sec, end_usec, rt, delta;
  607. X  int sleept;
  608. X  char buf[64], str[32];
  609. X  
  610. X  Argv = argv;
  611. X
  612. X  if(argc != 3 && argc != 1){
  613. X    fprintf(stderr, "usage: %s remotehost timeinterval\n", Argv[0]);
  614. X    exit(1);
  615. X  };
  616. X  
  617. X  if( argc == 1 ){
  618. X    host = (char*)malloc(64);
  619. X    loadParams(CONF, &sleept);
  620. X  }
  621. X  else{
  622. X    if(sscanf(Argv[2], "%d", &sleept) != 1){
  623. X      fprintf(stderr, "%s: parameter 2 must be an integer value\n", Argv[0]); 
  624. X      exit(1);
  625. X    };
  626. X    host = Argv[1];
  627. X  }
  628. X  
  629. X  localHost = (char*)malloc(64);
  630. X  gethostname(localHost, 64);
  631. X  
  632. X  if(strcmp(argv[0], "synmon") == 0) synmon = 1; 
  633. X  init_connection(&addr, host);
  634. X  
  635. X  sprintf(str, "synclockd %s started", VERSION);
  636. X  LOG(str);
  637. X  
  638. X  if(synmon){
  639. X    printf("remote host   = %s\n", host);
  640. X    printf("time interval = %d\n", sleept);
  641. X  }
  642. X  else
  643. X    handle_sigs();
  644. X  
  645. X  while(1){
  646. X    if(synmon)
  647. X      printf("\npolling %s:\n", host);
  648. X    
  649. X    time_get(&start_sec, &start_usec);
  650. X    ret = getrtime(&addr, &time);
  651. X    time_get(&end_sec, &end_usec);
  652. X    
  653. X    if(ret != 0){  /* rtimel timed stderr. Retry later */
  654. X      if(synmon) 
  655. X        fprintf(stderr, "%s: connection to %s timed out\n", Argv[0], host);
  656. X      else
  657. X    LOG("connection to time server timed out");
  658. X      sleep(sleept);
  659. X      continue;
  660. X    }
  661. X    
  662. X    ret = gettimeofday(<ime, (struct timezone*)0);
  663. X    if(ret != 0){
  664. X      fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
  665. X      LOG("panic: gettimeofday failed!");
  666. X      exit(1);
  667. X    }
  668. X    
  669. X    rt = calc_roundtrip(start_sec, start_usec, end_sec, end_usec);
  670. X    
  671. X    /* 
  672. X     * since gettimeofday()'s _real_ exactness is around 1/60 second,
  673. X     * most rountripdelays in a LAN will become 0 if we rely on
  674. X     * gettimeofday().
  675. X     * Too small values ( < MIN_RT ) are corrected to AVG_RT. Both values
  676. X     * derive from measurements using an exact timer we undertook
  677. X     * in a Ethernet LAN.
  678. X     */
  679. X    if(rt < MIN_RT) rt = AVG_RT;
  680. X    
  681. X    /*
  682. X     * Next we look if the actual roundtrip is smaller than the corrected,
  683. X     * shortest roundtrip so far:
  684. X     * rt < rt_min + 2 * (1+DRIFT) * elapsed_time.
  685. X     * With rt being the actual roundtrip, rt_min the shortest roundtrip
  686. X     * encountered so far and the rest a parameter taking into
  687. X     * account the maximal drift of two clocks.
  688. X     */
  689. X    if( rt_is_lower((double)rt, (double)start_sec, (double)start_usec, synmon) ){
  690. X      if(synmon){ 
  691. X        printf("roundtrip is lower       : %ld usec\n", rt);
  692. X        printf("remote time: %ld sec, %ld usec\n", time.tv_sec, time.tv_usec);
  693. X        printf("local time : %ld sec, %ld usec\n", ltime.tv_sec, ltime.tv_usec);
  694. X      }
  695. X      
  696. X      /* compute time-delta between remote and local:
  697. X       * roundtrip/2 + remote - local .
  698. X       * If delta is positive, then speed up clock, else slow down.
  699. X       */
  700. X      delta =  rt/2 +  
  701. X          calc_delta(ltime.tv_sec, ltime.tv_usec, time.tv_sec, time.tv_usec);
  702. X      
  703. X      if(delta != 0){
  704. X    
  705. X        ntime.tv_sec  = delta/1000000;
  706. X        ntime.tv_usec = delta - ntime.tv_sec * 1000000;
  707. X    
  708. X    if(!synmon){
  709. X          ret = adjtime(&ntime, 0);
  710. X          if(ret != 0){
  711. X            fprintf(stderr, "%s: adjtime: %s\n", Argv[0], sys_errlist[errno]);
  712. X        LOG("panic: adjtime failed");
  713. X            exit(1);
  714. X          }
  715. X        }
  716. X    
  717. X    /* Look if the difference between local and remote clock
  718. X     * is "suspiciously" high. If so, log it.
  719. X         */
  720. X    rt = calc_delta(time.tv_sec, time.tv_usec, ltime.tv_sec,
  721. X            ltime.tv_usec);
  722. X    
  723. X    if(abs(rt) > SUSPICIOUS){
  724. X      sprintf(buf, "suspicious time difference: %ld", rt);
  725. X      LOG(buf);
  726. X        }
  727. X      }
  728. X      
  729. X      if(synmon){
  730. X        printf("advancing local clock by %ld sec, %ld usec\n", 
  731. X           ntime.tv_sec, ntime.tv_usec);
  732. X      }
  733. X    }  
  734. X    else 
  735. X      if(synmon)
  736. X    printf("roundtrip is *not* lower : %d usec\n", rt);
  737. X    
  738. X    sleep(sleept);
  739. X    
  740. X    /* allows to configure synclockd at runtime:
  741. X     */
  742. X    if(argc == 1)  
  743. X      loadParams(CONF, host, &sleept);
  744. X  }
  745. X}
  746. END_OF_FILE
  747. if test 9596 -ne `wc -c <'synclockd.c'`; then
  748.     echo shar: \"'synclockd.c'\" unpacked with wrong size!
  749. fi
  750. # end of 'synclockd.c'
  751. fi
  752. if test -f 'synclockd.conf' -a "${1}" != "-c" ; then 
  753.   echo shar: Will not clobber existing file \"'synclockd.conf'\"
  754. else
  755. echo shar: Extracting \"'synclockd.conf'\" \(26 characters\)
  756. sed "s/^X//" >'synclockd.conf' <<'END_OF_FILE'
  757. Xhost.foo.bar.edu   1800 
  758. X
  759. END_OF_FILE
  760. if test 26 -ne `wc -c <'synclockd.conf'`; then
  761.     echo shar: \"'synclockd.conf'\" unpacked with wrong size!
  762. fi
  763. # end of 'synclockd.conf'
  764. fi
  765. if test -f 'synservd.c' -a "${1}" != "-c" ; then 
  766.   echo shar: Will not clobber existing file \"'synservd.c'\"
  767. else
  768. echo shar: Extracting \"'synservd.c'\" \(3072 characters\)
  769. sed "s/^X//" >'synservd.c' <<'END_OF_FILE'
  770. X/* (C) Silvano Maffeis, maffeis@ifi.unizh.ch             
  771. X * University of Zurich, Switzerland 1992            
  772. X *
  773. X * synservd.c: server daemon that listens on udp socket and quickly
  774. X *             returns the local time using gettimeofday().
  775. X */
  776. X
  777. X#include <stdio.h>
  778. X#include <sys/types.h>
  779. X#include <sys/socket.h>
  780. X#include <netinet/in.h>
  781. X#include <arpa/inet.h>
  782. X#include <netdb.h>
  783. X#include <ctype.h>
  784. X#include <errno.h>
  785. X#include <signal.h>
  786. X#include <sys/time.h>
  787. X
  788. X#define BUFFERSIZE sizeof(struct timeval)
  789. X
  790. Xextern errno;
  791. Xextern char *sys_errlist[];
  792. Xstruct sockaddr_in sin;
  793. Xint sock;
  794. Xchar  **Argv;
  795. X
  796. Xint setup_connection(){
  797. X  int s;
  798. X  int length;
  799. X  struct hostent *gethostbyname();
  800. X  struct servent *servent;
  801. X  
  802. X  s = socket(AF_INET, SOCK_DGRAM, 0);
  803. X  if (s < 0) {
  804. X    fprintf(stderr, "%s: opening udp socket\n", Argv[0]); 
  805. X    exit(1);
  806. X  }
  807. X  
  808. X  /* Connect socket using name specified by command line. */
  809. X  sin.sin_family = AF_INET;
  810. X  sin.sin_addr.s_addr = INADDR_ANY;
  811. X  
  812. X#ifndef PORT
  813. X  servent = getservbyname("utime", "udp");
  814. X  if(servent == NULL){
  815. X    fprintf(stderr, "%s: getservbyname: %s\n", Argv[0], sys_errlist[errno]);
  816. X    exit(1);
  817. X  };
  818. X  sin.sin_port = htons(servent->s_port);
  819. X#else
  820. X  sin.sin_port = htons(PORT);
  821. X#endif PORT
  822. X  
  823. X  if(bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0){
  824. X    fprintf(stderr, "%s: cannot bind\n", Argv[0]); 
  825. X    exit(1);
  826. X  }
  827. X  
  828. X  /* find socket# */
  829. X  
  830. X  length = sizeof(sin);
  831. X  if (getsockname(s, &sin, &length)) {
  832. X    fprintf(stderr, "%s: getsockname\n", Argv[0]); 
  833. X    exit(1);
  834. X  }
  835. X  fprintf(stderr, "Socket has port #%d\n", ntohs(sin.sin_port));
  836. X  
  837. X  listen(s, 5);
  838. X  return(s);
  839. X}
  840. X
  841. X#if defined(SYSV)
  842. Xvoid term_fcn(sig)
  843. X#else
  844. X     term_fcn(sig)   
  845. X#endif SYSV
  846. X     int sig;
  847. X{
  848. X  if(signal(sig, SIG_IGN) == SIG_ERR){
  849. X    fprintf(stderr, "%s: signal\n", Argv[0]); 
  850. X    exit(1);
  851. X  }
  852. X  
  853. X  fprintf(stderr, "%s: Got a kill signal!\n\n", Argv[0]);
  854. X  
  855. X  shutdown(sock,2); 
  856. X  close(sock);
  857. X  exit(1);
  858. X}
  859. X
  860. Xint handle_sigs(){
  861. X  if(signal(SIGHUP, SIG_IGN) == SIG_ERR)
  862. X    return(0);
  863. X  
  864. X  if(signal(SIGINT, SIG_IGN) == SIG_ERR)
  865. X    return(0);
  866. X  
  867. X  if(signal(SIGQUIT, SIG_IGN) == SIG_ERR)
  868. X    return(0);
  869. X  
  870. X  if(signal(SIGTERM, term_fcn) == SIG_ERR)
  871. X    return(0);
  872. X  
  873. X  return(1);
  874. X}
  875. X
  876. X
  877. Xmain(argc, argv)
  878. X     int argc;
  879. X     char *argv[];
  880. X{
  881. X  char in[BUFFERSIZE], out[BUFFERSIZE];
  882. X  struct timeval tv;
  883. X  struct sockaddr sa;
  884. X  int size = sizeof(sa);
  885. X  
  886. X  Argv = argv;
  887. X  
  888. X  if(! handle_sigs()){
  889. X    fprintf(stderr, "%s: handle sigs\n", Argv[0]); 
  890. X    exit(1);
  891. X  };
  892. X  
  893. X  sock=setup_connection();
  894. X  
  895. X  while(1){
  896. X    
  897. X    if (recvfrom(sock, in, BUFFERSIZE, 0, &sa, &size) < 0){
  898. X      fprintf(stderr, "%s: recvfrom udp socket\n", Argv[0]); 
  899. X      exit(1);
  900. X    };
  901. X    
  902. X    if (gettimeofday(&tv, 0) < 0){
  903. X      fprintf(stderr, "%s: gettimeofday: %s\n", Argv[0], sys_errlist[errno]);
  904. X      exit(1);
  905. X    };
  906. X    
  907. X    memcpy(out, &tv.tv_sec, sizeof(long));
  908. X    memcpy(&out[sizeof(long)], &tv.tv_usec, sizeof(long));
  909. X    
  910. X    if(sendto(sock, out, BUFFERSIZE, 0, &sa, size) < 0){
  911. X      fprintf(stderr, "%s: sendto udp socket\n", Argv[0]); 
  912. X      exit(1);
  913. X    };
  914. X  }
  915. X}
  916. X
  917. X
  918. END_OF_FILE
  919. if test 3072 -ne `wc -c <'synservd.c'`; then
  920.     echo shar: \"'synservd.c'\" unpacked with wrong size!
  921. fi
  922. # end of 'synservd.c'
  923. fi
  924. echo shar: End of shell archive.
  925. exit 0
  926. -- 
  927. Silvano Maffeis       CS Dept. University of Zurich, Switzerland
  928.    RFC822: maffeis@ifi.unizh.ch            voice: +411 257 43 27
  929.    X.400: /S=maffeis/OU=ifi/O=unizh/PRMD=SWITCH/ADMD=ARCOM/C=CH/
  930.