📄 timed.c
字号:
/*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";#endif /* not lint */#ifdef sgi#ident "$Revision: 1.25 $"#endif /* sgi */#define TSPTYPES#include "globals.h"#include <net/if.h>#include <sys/file.h>#include <sys/ioctl.h>#include <setjmp.h>#include "pathnames.h"#include <math.h>#include <sys/types.h>#include <sys/times.h>#ifdef sgi#include <unistd.h>#include <sys/syssgi.h>#include <sys/schedctl.h>#endif /* sgi */int trace = 0;int sock, sock_raw = -1;int status = 0;u_short sequence; /* sequence number */long delay1;long delay2;int nslavenets; /* nets were I could be a slave */int nmasternets; /* nets were I could be a master */int nignorednets; /* ignored nets */int nnets; /* nets I am connected to */FILE *fd; /* trace file FD */jmp_buf jmpenv;struct netinfo *nettab = 0;struct netinfo *slavenet;int Mflag;int justquit = 0;int debug;static struct nets { char *name; long net; struct nets *next;} *nets = 0;struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */static struct goodhost { /* hosts that we trust */ char name[MAXHOSTNAMELEN+1]; struct goodhost *next; char perm;} *goodhosts;static char *goodgroup; /* net group of trusted hosts */static void checkignorednets __P((void));static void pickslavenet __P((struct netinfo *));static void add_good_host __P((char *, int));#ifdef sgichar *timetrim_fn;char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n";char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;";long timetrim;double tot_adj, hr_adj; /* totals in nsec */double tot_ticks, hr_ticks;int bufspace = 60*1024;#endif/* * The timedaemons synchronize the clocks of hosts in a local area network. * One daemon runs as master, all the others as slaves. The master * performs the task of computing clock differences and sends correction * values to the slaves. * Slaves start an election to choose a new master when the latter disappears * because of a machine crash, network partition, or when killed. * A resolution protocol is used to kill all but one of the masters * that happen to exist in segments of a partitioned network when the * network partition is fixed. * * Authors: Riccardo Gusella & Stefano Zatti * * overhauled at Silicon Graphics */intmain(argc, argv) int argc; char *argv[];{ int on; int ret; int nflag, iflag; struct timeval ntime; struct servent *srvp; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq ifreq, ifreqf, *ifr; register struct netinfo *ntp; struct netinfo *ntip; struct netinfo *savefromnet; struct netent *nentp; struct nets *nt; struct sockaddr_in server; u_short port; char c; extern char *optarg; extern int optind, opterr;#ifdef sgi FILE *timetrim_st;#endif#define IN_MSG "timed: -i and -n make no sense together\n"#ifdef sgi struct tms tms;#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n"#else#ifdef HAVENIS#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"#else#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"#endif /* HAVENIS */#endif /* sgi */#ifdef lint ntip = NULL;#endif on = 1; nflag = OFF; iflag = OFF;#ifdef sgi if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) { perror("timed: syssgi(GETTIMETRIM)"); timetrim = 0; } tot_ticks = hr_ticks = times(&tms);#endif /* sgi */ opterr = 0; while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != EOF) { switch (c) { case 'M': Mflag = 1; break; case 't': trace = 1; break; case 'n': if (iflag) { fprintf(stderr, IN_MSG); exit(1); } else { nflag = ON; addnetname(optarg); } break; case 'i': if (nflag) { fprintf(stderr, IN_MSG); exit(1); } else { iflag = ON; addnetname(optarg); } break; case 'F': add_good_host(optarg,1); while (optind < argc && argv[optind][0] != '-') add_good_host(argv[optind++], 1); break; case 'd': debug = 1; break; case 'G': if (goodgroup != 0) { fprintf(stderr,"timed: only one net group\n"); exit(1); } goodgroup = optarg; break;#ifdef sgi case 'P': timetrim_fn = optarg; timetrim_st = fopen(timetrim_fn, "r+"); if (0 == timetrim_st) { if (errno != ENOENT) { (void)fprintf(stderr,"timed: "); perror(timetrim_fn); timetrim_fn = 0; } } else { int i; long trim; double adj, ticks; i = fscanf(timetrim_st, timetrim_rpat, &trim, &adj, &ticks); if (i < 1 || trim > MAX_TRIM || trim < -MAX_TRIM || i == 2 || (i == 3 && trim != rint(adj*CLK_TCK/ticks))) { if (trace && i != EOF) (void)fprintf(stderr, "timed: unrecognized contents in %s\n", timetrim_fn); } else { if (0 > syssgi(SGI_SETTIMETRIM, trim)) { perror("timed: syssgi(SETTIMETRIM)"); } else { timetrim = trim; } if (i == 3) { tot_adj = adj; tot_ticks -= ticks; } } (void)fclose(timetrim_st); } break;#endif /* sgi */ default: fprintf(stderr, USAGE); exit(1); break; } } if (optind < argc) { fprintf(stderr, USAGE); exit(1); } /* If we care about which machine is the master, then we must * be willing to be a master */ if (0 != goodgroup || 0 != goodhosts) Mflag = 1; if (gethostname(hostname, sizeof(hostname) - 1) < 0) { perror("gethostname"); exit(1); } self.l_bak = &self; self.l_fwd = &self; self.h_bak = &self; self.h_fwd = &self; self.head = 1; self.good = 1; if (goodhosts != 0) /* trust ourself */ add_good_host(hostname,1); srvp = getservbyname("timed", "udp"); if (srvp == 0) { fprintf(stderr, "unknown service 'timed/udp'\n"); exit(1); } port = srvp->s_port; server.sin_port = srvp->s_port; server.sin_family = AF_INET; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); exit(1); } if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) { perror("setsockopt"); exit(1); } if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { if (errno == EADDRINUSE) fprintf(stderr,"timed: time daemon already running\n"); else perror("bind"); exit(1); }#ifdef sgi /* * handle many slaves with our buffer */ if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace, sizeof(bufspace))) { perror("setsockopt"); exit(1); }#endif /* sgi */ /* choose a unique seed for random number generation */ (void)gettimeofday(&ntime, 0); srandom(ntime.tv_sec + ntime.tv_usec); sequence = random(); /* initial seq number */#ifndef sgi /* rounds kernel variable time to multiple of 5 ms. */ ntime.tv_sec = 0; ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000; (void)adjtime(&ntime, (struct timeval *)0);#endif /* sgi */ for (nt = nets; nt; nt = nt->next) { nentp = getnetbyname(nt->name); if (nentp == 0) { nt->net = inet_network(nt->name); if (nt->net != INADDR_NONE) nentp = getnetbyaddr(nt->net, AF_INET); } if (nentp != 0) { nt->net = nentp->n_net; } else if (nt->net == INADDR_NONE) { fprintf(stderr, "timed: unknown net %s\n", nt->name); exit(1); } else if (nt->net == INADDR_ANY) { fprintf(stderr, "timed: bad net %s\n", nt->name); exit(1); } else { fprintf(stderr, "timed: warning: %s unknown in /etc/networks\n", nt->name); } if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; } ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { perror("timed: get interface configuration"); exit(1); } ntp = NULL;#ifdef sgi#define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */#else#define size(p) max((p).sa_len, sizeof(p))#endif cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { ifr = (struct ifreq *)cp; if (ifr->ifr_addr.sa_family != AF_INET) continue; if (!ntp) ntp = (struct netinfo*)malloc(sizeof(struct netinfo)); bzero(ntp,sizeof(*ntp)); ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; ntp->status = NOMASTER; ifreq = *ifr; ifreqf = *ifr; if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) { perror("get interface flags"); continue; } if ((ifreqf.ifr_flags & IFF_UP) == 0) continue; if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 && (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) { continue; } if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { perror("get netmask"); continue; } ntp->mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; if (ifreqf.ifr_flags & IFF_BROADCAST) { if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { perror("get broadaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; /* What if the broadcast address is all ones? * So we cannot just mask ntp->dest_addr. */ ntp->net = ntp->my_addr; ntp->net.s_addr &= ntp->mask; } else { if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { perror("get destaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; ntp->net = ntp->dest_addr.sin_addr; } ntp->dest_addr.sin_port = port; for (nt = nets; nt; nt = nt->next) { if (ntp->net.s_addr == nt->net) break; } if (nflag && !nt || iflag && nt) continue; ntp->next = NULL; if (nettab == NULL) { nettab = ntp; } else { ntip->next = ntp; } ntip = ntp; ntp = NULL; } if (ntp) (void) free((char *)ntp); if (nettab == NULL) { fprintf(stderr, "timed: no network usable\n"); exit(1); }#ifdef sgi (void)schedctl(RENICE,0,10); /* run fast to get good time */ /* ticks to delay before responding to a broadcast */ delay1 = casual(0, CLK_TCK/10);#else /* microseconds to delay before responding to a broadcast */ delay1 = casual(1, 100*1000);#endif /* sgi */ /* election timer delay in secs. */ delay2 = casual(MINTOUT, MAXTOUT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -