home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / synclckd / part01 < prev    next >
Encoding:
Text File  |  1993-01-09  |  24.3 KB  |  927 lines

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