Annotation of 43BSD/etc/timed/master.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1985 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[] = "@(#)master.c   2.14 (Berkeley) 6/5/86";
        !             9: #endif not lint
        !            10: 
        !            11: #include "globals.h"
        !            12: #include <protocols/timed.h>
        !            13: #include <sys/file.h>
        !            14: #include <setjmp.h>
        !            15: #include <utmp.h>
        !            16: 
        !            17: extern int machup;
        !            18: extern int measure_delta;
        !            19: extern jmp_buf jmpenv;
        !            20: 
        !            21: extern u_short sequence;
        !            22: 
        !            23: #ifdef MEASURE
        !            24: int header;
        !            25: FILE *fp = NULL;
        !            26: #endif
        !            27: 
        !            28: /*
        !            29:  * The main function of `master' is to periodically compute the differences 
        !            30:  * (deltas) between its clock and the clocks of the slaves, to compute the 
        !            31:  * network average delta, and to send to the slaves the differences between 
        !            32:  * their individual deltas and the network delta.
        !            33:  * While waiting, it receives messages from the slaves (i.e. requests for
        !            34:  * master's name, remote requests to set the network time, ...), and
        !            35:  * takes the appropriate action.
        !            36:  */
        !            37: 
        !            38: master()
        !            39: {
        !            40:        int ind;
        !            41:        long pollingtime;
        !            42:        struct timeval wait;
        !            43:        struct timeval time;
        !            44:        struct timeval otime;
        !            45:        struct timezone tzone;
        !            46:        struct tsp *msg, to;
        !            47:        struct sockaddr_in saveaddr;
        !            48:        int findhost();
        !            49:        char *date();
        !            50:        struct tsp *readmsg();
        !            51:        struct tsp *answer, *acksend();
        !            52:        char olddate[32];
        !            53:        struct sockaddr_in server;
        !            54:        register struct netinfo *ntp;
        !            55: 
        !            56: #ifdef MEASURE
        !            57:        if (fp == NULL) {
        !            58:                fp = fopen("/usr/adm/timed.masterlog", "w");
        !            59:                setlinebuf(fp);
        !            60:        }
        !            61: #endif
        !            62: 
        !            63:        syslog(LOG_INFO, "This machine is master");
        !            64:        if (trace)
        !            65:                fprintf(fd, "THIS MACHINE IS MASTER\n");
        !            66: 
        !            67:        for (ntp = nettab; ntp != NULL; ntp = ntp->next)
        !            68:                if (ntp->status == MASTER)
        !            69:                        masterup(ntp);
        !            70:        pollingtime = 0;
        !            71: 
        !            72: loop:
        !            73:        (void)gettimeofday(&time, (struct timezone *)0);
        !            74:        if (time.tv_sec >= pollingtime) {
        !            75:                pollingtime = time.tv_sec + SAMPLEINTVL;
        !            76:                synch(0L);
        !            77: 
        !            78:                for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
        !            79:                        to.tsp_type = TSP_LOOP;
        !            80:                        to.tsp_vers = TSPVERSION;
        !            81:                        to.tsp_seq = sequence++;
        !            82:                        to.tsp_hopcnt = 10;
        !            83:                        (void)strcpy(to.tsp_name, hostname);
        !            84:                        bytenetorder(&to);
        !            85:                        if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
        !            86:                            &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
        !            87:                                syslog(LOG_ERR, "sendto: %m");
        !            88:                                exit(1);
        !            89:                        }
        !            90:                }
        !            91:        }
        !            92: 
        !            93:        wait.tv_sec = pollingtime - time.tv_sec;
        !            94:        wait.tv_usec = 0;
        !            95:        msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
        !            96:        if (msg != NULL) {
        !            97:                switch (msg->tsp_type) {
        !            98: 
        !            99:                case TSP_MASTERREQ:
        !           100:                        break;
        !           101:                case TSP_SLAVEUP:
        !           102:                        ind = addmach(msg->tsp_name, &from);
        !           103:                        newslave(ind, msg->tsp_seq);
        !           104:                        break;
        !           105:                case TSP_SETDATE:
        !           106:                        saveaddr = from;
        !           107:                        /*
        !           108:                         * the following line is necessary due to syslog
        !           109:                         * calling ctime() which clobbers the static buffer
        !           110:                         */
        !           111:                        (void)strcpy(olddate, date());
        !           112:                        (void)gettimeofday(&time, &tzone);
        !           113:                        otime = time;
        !           114:                        time.tv_sec = msg->tsp_time.tv_sec;
        !           115:                        time.tv_usec = msg->tsp_time.tv_usec;
        !           116:                        (void)settimeofday(&time, &tzone);
        !           117:                        syslog(LOG_NOTICE, "date changed from: %s", olddate);
        !           118:                        logwtmp(otime, time);
        !           119:                        msg->tsp_type = TSP_DATEACK;
        !           120:                        msg->tsp_vers = TSPVERSION;
        !           121:                        (void)strcpy(msg->tsp_name, hostname);
        !           122:                        bytenetorder(msg);
        !           123:                        if (sendto(sock, (char *)msg, sizeof(struct tsp), 0,
        !           124:                            &saveaddr, sizeof(struct sockaddr_in)) < 0) {
        !           125:                                syslog(LOG_ERR, "sendto: %m");
        !           126:                                exit(1);
        !           127:                        }
        !           128:                        spreadtime();
        !           129:                        pollingtime = 0;
        !           130:                        break;
        !           131:                case TSP_SETDATEREQ:
        !           132:                        ind = findhost(msg->tsp_name);
        !           133:                        if (ind < 0) { 
        !           134:                            syslog(LOG_WARNING,
        !           135:                                "DATEREQ from uncontrolled machine");
        !           136:                            break;
        !           137:                        }
        !           138:                        if (hp[ind].seq !=  msg->tsp_seq) {
        !           139:                                hp[ind].seq = msg->tsp_seq;
        !           140:                                /*
        !           141:                                 * the following line is necessary due to syslog
        !           142:                                 * calling ctime() which clobbers the static buffer
        !           143:                                 */
        !           144:                                (void)strcpy(olddate, date());
        !           145:                                (void)gettimeofday(&time, &tzone);
        !           146:                                otime = time;
        !           147:                                time.tv_sec = msg->tsp_time.tv_sec;
        !           148:                                time.tv_usec = msg->tsp_time.tv_usec;
        !           149:                                (void)settimeofday(&time, &tzone);
        !           150:                                syslog(LOG_NOTICE,
        !           151:                                    "date changed by %s from: %s",
        !           152:                                    msg->tsp_name, olddate);
        !           153:                                logwtmp(otime, time);
        !           154:                                spreadtime();
        !           155:                                pollingtime = 0;
        !           156:                        }
        !           157:                        break;
        !           158:                case TSP_MSITE:
        !           159:                case TSP_MSITEREQ:
        !           160:                        break;
        !           161:                case TSP_TRACEON:
        !           162:                        if (!(trace)) {
        !           163:                                fd = fopen(tracefile, "w");
        !           164:                                setlinebuf(fd);
        !           165:                                fprintf(fd, "Tracing started on: %s\n\n", 
        !           166:                                                        date());
        !           167:                        }
        !           168:                        trace = ON;
        !           169:                        break;
        !           170:                case TSP_TRACEOFF:
        !           171:                        if (trace) {
        !           172:                                fprintf(fd, "Tracing ended on: %s\n", date());
        !           173:                                (void)fclose(fd);
        !           174:                        }
        !           175: #ifdef GPROF
        !           176:                        moncontrol(0);
        !           177:                        _mcleanup();
        !           178:                        moncontrol(1);
        !           179: #endif
        !           180:                        trace = OFF;
        !           181:                        break;
        !           182:                case TSP_ELECTION:
        !           183:                        to.tsp_type = TSP_QUIT;
        !           184:                        (void)strcpy(to.tsp_name, hostname);
        !           185:                        server = from;
        !           186:                        answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
        !           187:                            (struct netinfo *)NULL);
        !           188:                        if (answer == NULL) {
        !           189:                                syslog(LOG_ERR, "election error");
        !           190:                        } else {
        !           191:                                (void) addmach(msg->tsp_name, &from);
        !           192:                        }
        !           193:                        pollingtime = 0;
        !           194:                        break;
        !           195:                case TSP_CONFLICT:
        !           196:                        /*
        !           197:                         * After a network partition, there can be 
        !           198:                         * more than one master: the first slave to 
        !           199:                         * come up will notify here the situation.
        !           200:                         */
        !           201: 
        !           202:                        (void)strcpy(to.tsp_name, hostname);
        !           203: 
        !           204:                        if (fromnet == NULL)
        !           205:                                break;
        !           206:                        for(;;) {
        !           207:                                to.tsp_type = TSP_RESOLVE;
        !           208:                                answer = acksend(&to, &fromnet->dest_addr,
        !           209:                                    (char *)ANYADDR, TSP_MASTERACK, fromnet);
        !           210:                                if (answer == NULL)
        !           211:                                        break;
        !           212:                                to.tsp_type = TSP_QUIT;
        !           213:                                server = from;
        !           214:                                msg = acksend(&to, &server, answer->tsp_name,
        !           215:                                    TSP_ACK, (struct netinfo *)NULL);
        !           216:                                if (msg == NULL) {
        !           217:                                        syslog(LOG_ERR, "error on sending QUIT");
        !           218:                                } else {
        !           219:                                        (void) addmach(answer->tsp_name, &from);
        !           220:                                }
        !           221:                        }
        !           222:                        masterup(fromnet);
        !           223:                        pollingtime = 0;
        !           224:                        break;
        !           225:                case TSP_RESOLVE:
        !           226:                        /*
        !           227:                         * do not want to call synch() while waiting
        !           228:                         * to be killed!
        !           229:                         */
        !           230:                        (void)gettimeofday(&time, (struct timezone *)0);
        !           231:                        pollingtime = time.tv_sec + SAMPLEINTVL;
        !           232:                        break;
        !           233:                case TSP_QUIT:
        !           234:                        /* become slave */
        !           235: #ifdef MEASURE
        !           236:                        if (fp != NULL) {
        !           237:                                (void)fclose(fp);
        !           238:                                fp = NULL;
        !           239:                        }
        !           240: #endif
        !           241:                        longjmp(jmpenv, 2);
        !           242:                        break;
        !           243:                case TSP_LOOP:
        !           244:                        /*
        !           245:                         * We should not have received this from a net
        !           246:                         * we are master on.  There must be two masters
        !           247:                         * in this case.
        !           248:                         */
        !           249:                        to.tsp_type = TSP_QUIT;
        !           250:                        (void)strcpy(to.tsp_name, hostname);
        !           251:                        server = from;
        !           252:                        answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
        !           253:                                (struct netinfo *)NULL);
        !           254:                        if (answer == NULL) {
        !           255:                                syslog(LOG_WARNING,
        !           256:                                    "loop breakage: no reply to QUIT");
        !           257:                        } else {
        !           258:                                (void)addmach(msg->tsp_name, &from);
        !           259:                        }
        !           260:                default:
        !           261:                        if (trace) {
        !           262:                                fprintf(fd, "garbage: ");
        !           263:                                print(msg, &from);
        !           264:                        }
        !           265:                        break;
        !           266:                }
        !           267:        }
        !           268:        goto loop;
        !           269: }
        !           270: 
        !           271: /*
        !           272:  * `synch' synchronizes all the slaves by calling measure, 
        !           273:  * networkdelta and correct 
        !           274:  */
        !           275: 
        !           276: synch(mydelta)
        !           277: long mydelta;
        !           278: {
        !           279:        int i;
        !           280:        int measure_status;
        !           281:        long netdelta;
        !           282:        struct timeval tack;
        !           283: #ifdef MEASURE
        !           284: #define MAXLINES       8
        !           285:        static int lines = 1;
        !           286:        struct timeval start, end;
        !           287: #endif
        !           288:        int measure();
        !           289:        int correct();
        !           290:        long networkdelta();
        !           291:        char *date();
        !           292: 
        !           293:        if (slvcount > 1) {
        !           294: #ifdef MEASURE
        !           295:                (void)gettimeofday(&start, (struct timezone *)0);
        !           296:                if (header == ON || --lines == 0) {
        !           297:                        fprintf(fp, "%s\n", date());
        !           298:                        for (i=0; i<slvcount; i++)
        !           299:                                fprintf(fp, "%.7s\t", hp[i].name);
        !           300:                        fprintf(fp, "\n");
        !           301:                        lines = MAXLINES;
        !           302:                        header = OFF;
        !           303:                }
        !           304: #endif
        !           305:                machup = 1;
        !           306:                hp[0].delta = 0;
        !           307:                for(i=1; i<slvcount; i++) {
        !           308:                        tack.tv_sec = 0;
        !           309:                        tack.tv_usec = 500000;
        !           310:                        if ((measure_status = measure(&tack, &hp[i].addr)) <0) {
        !           311:                                syslog(LOG_ERR, "measure: %m");
        !           312:                                exit(1);
        !           313:                        }
        !           314:                        hp[i].delta = measure_delta;
        !           315:                        if (measure_status == GOOD)
        !           316:                                machup++;
        !           317:                }
        !           318:                if (status & SLAVE) {
        !           319:                        /* called by a submaster */
        !           320:                        if (trace)
        !           321:                                fprintf(fd, "submaster correct: %d ms.\n",
        !           322:                                    mydelta);
        !           323:                        correct(mydelta);       
        !           324:                } else {
        !           325:                        if (machup > 1) {
        !           326:                                netdelta = networkdelta();
        !           327:                                if (trace)
        !           328:                                        fprintf(fd,
        !           329:                                            "master correct: %d ms.\n",
        !           330:                                            mydelta);
        !           331:                                correct(netdelta);
        !           332:                        }
        !           333:                }
        !           334: #ifdef MEASURE
        !           335:                gettimeofday(&end, 0);
        !           336:                end.tv_sec -= start.tv_sec;
        !           337:                end.tv_usec -= start.tv_usec;
        !           338:                if (end.tv_usec < 0) {
        !           339:                        end.tv_sec -= 1;
        !           340:                        end.tv_usec += 1000000;
        !           341:                }
        !           342:                fprintf(fp, "%d ms.\n", (end.tv_sec*1000+end.tv_usec/1000));
        !           343: #endif
        !           344:                for(i=1; i<slvcount; i++) {
        !           345:                        if (hp[i].delta == HOSTDOWN) {
        !           346:                                rmmach(i);
        !           347: #ifdef MEASURE
        !           348:                                header = ON;
        !           349: #endif
        !           350:                        }
        !           351:                }
        !           352:        } else {
        !           353:                if (status & SLAVE) {
        !           354:                        correct(mydelta);
        !           355:                }
        !           356:        }
        !           357: }
        !           358: 
        !           359: /*
        !           360:  * 'spreadtime' sends the time to each slave after the master
        !           361:  * has received the command to set the network time 
        !           362:  */
        !           363: 
        !           364: spreadtime()
        !           365: {
        !           366:        int i;
        !           367:        struct tsp to;
        !           368:        struct tsp *answer, *acksend();
        !           369: 
        !           370:        for(i=1; i<slvcount; i++) {
        !           371:                to.tsp_type = TSP_SETTIME;
        !           372:                (void)strcpy(to.tsp_name, hostname);
        !           373:                (void)gettimeofday(&to.tsp_time, (struct timezone *)0);
        !           374:                answer = acksend(&to, &hp[i].addr, hp[i].name, TSP_ACK,
        !           375:                    (struct netinfo *)NULL);
        !           376:                if (answer == NULL) {
        !           377:                        syslog(LOG_WARNING,
        !           378:                            "no reply to SETTIME from: %s", hp[i].name);
        !           379:                }
        !           380:        }
        !           381: }
        !           382: 
        !           383: findhost(name)
        !           384: char *name;
        !           385: {
        !           386:        int i;
        !           387:        int ind;
        !           388: 
        !           389:        ind = -1;
        !           390:        for (i=1; i<slvcount; i++) {
        !           391:                if (strcmp(name, hp[i].name) == 0) {
        !           392:                        ind = i;
        !           393:                        break;
        !           394:                }
        !           395:        }
        !           396:        return(ind);
        !           397: }
        !           398: 
        !           399: /*
        !           400:  * 'addmach' adds a host to the list of controlled machines
        !           401:  * if not already there 
        !           402:  */
        !           403: 
        !           404: addmach(name, addr)
        !           405: char *name;
        !           406: struct sockaddr_in *addr;
        !           407: {
        !           408:        int ret;
        !           409:        int findhost();
        !           410: 
        !           411:        ret = findhost(name);
        !           412:        if (ret < 0) {
        !           413:                hp[slvcount].addr = *addr;
        !           414:                hp[slvcount].name = (char *)malloc(MAXHOSTNAMELEN);
        !           415:                (void)strcpy(hp[slvcount].name, name);
        !           416:                hp[slvcount].seq = 0;
        !           417:                ret = slvcount;
        !           418:                if (slvcount < NHOSTS)
        !           419:                        slvcount++;
        !           420:                else {
        !           421:                        syslog(LOG_ERR, "no more slots in host table");
        !           422:                }
        !           423:        } else {
        !           424:                /* need to clear sequence number anyhow */
        !           425:                hp[ret].seq = 0;
        !           426:        }
        !           427: #ifdef MEASURE
        !           428:        header = ON;
        !           429: #endif
        !           430:        return(ret);
        !           431: }
        !           432: 
        !           433: /*
        !           434:  * Remove all the machines from the host table that exist on the given
        !           435:  * network.  This is called when a master transitions to a slave on a
        !           436:  * given network.
        !           437:  */
        !           438: 
        !           439: rmnetmachs(ntp)
        !           440:        register struct netinfo *ntp;
        !           441: {
        !           442:        int i;
        !           443: 
        !           444:        if (trace)
        !           445:                prthp();
        !           446:        for (i = 1; i < slvcount; i++)
        !           447:                if ((hp[i].addr.sin_addr.s_addr & ntp->mask) == ntp->net)
        !           448:                        rmmach(i--);
        !           449:        if (trace)
        !           450:                prthp();
        !           451: }
        !           452: 
        !           453: /*
        !           454:  * remove the machine with the given index in the host table.
        !           455:  */
        !           456: rmmach(ind)
        !           457:        int ind;
        !           458: {
        !           459:        if (trace)
        !           460:                fprintf(fd, "rmmach: %s\n", hp[ind].name);
        !           461:        free(hp[ind].name);
        !           462:        hp[ind] = hp[--slvcount];
        !           463: }
        !           464: 
        !           465: prthp()
        !           466: {
        !           467:        int i;
        !           468: 
        !           469:        fprintf(fd, "host table:");
        !           470:        for (i=1; i<slvcount; i++)
        !           471:                fprintf(fd, " %s", hp[i].name);
        !           472:        fprintf(fd, "\n");
        !           473: }
        !           474: 
        !           475: masterup(net)
        !           476: struct netinfo *net;
        !           477: {
        !           478:        struct timeval wait;
        !           479:        struct tsp to, *msg, *readmsg();
        !           480: 
        !           481:        to.tsp_type = TSP_MASTERUP;
        !           482:        to.tsp_vers = TSPVERSION;
        !           483:        (void)strcpy(to.tsp_name, hostname);
        !           484:        bytenetorder(&to);
        !           485:        if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, &net->dest_addr,
        !           486:            sizeof(struct sockaddr_in)) < 0) {
        !           487:                syslog(LOG_ERR, "sendto: %m");
        !           488:                exit(1);
        !           489:        }
        !           490: 
        !           491:        for (;;) {
        !           492:                wait.tv_sec = 1;
        !           493:                wait.tv_usec = 0;
        !           494:                msg = readmsg(TSP_SLAVEUP, (char *)ANYADDR, &wait, net);
        !           495:                if (msg != NULL) {
        !           496:                        (void) addmach(msg->tsp_name, &from);
        !           497:                } else
        !           498:                        break;
        !           499:        }
        !           500: }
        !           501: 
        !           502: newslave(ind, seq)
        !           503: u_short seq;
        !           504: {
        !           505:        struct tsp to;
        !           506:        struct tsp *answer, *acksend();
        !           507: 
        !           508:        if (trace)
        !           509:                prthp();
        !           510:        if (seq == 0 || hp[ind].seq !=  seq) {
        !           511:                hp[ind].seq = seq;
        !           512:                to.tsp_type = TSP_SETTIME;
        !           513:                (void)strcpy(to.tsp_name, hostname);
        !           514:                /*
        !           515:                 * give the upcoming slave the time
        !           516:                 * to check its input queue before
        !           517:                 * setting the time
        !           518:                 */
        !           519:                sleep(1);
        !           520:                (void) gettimeofday(&to.tsp_time,
        !           521:                    (struct timezone *)0);
        !           522:                answer = acksend(&to, &hp[ind].addr,
        !           523:                    hp[ind].name, TSP_ACK,
        !           524:                    (struct netinfo *)NULL);
        !           525:                if (answer == NULL) {
        !           526:                        syslog(LOG_WARNING,
        !           527:                            "no reply to initial SETTIME from: %s",
        !           528:                            hp[ind].name);
        !           529:                        rmmach(ind);
        !           530:                }
        !           531:        }
        !           532: }
        !           533: 
        !           534: char *wtmpfile = "/usr/adm/wtmp";
        !           535: struct utmp wtmp[2] = {
        !           536:        { "|", "", "", 0 },
        !           537:        { "{", "", "", 0 }
        !           538: };
        !           539: 
        !           540: logwtmp(otime, ntime)
        !           541: struct timeval otime, ntime;
        !           542: {
        !           543:        int f;
        !           544: 
        !           545:        wtmp[0].ut_time = otime.tv_sec + (otime.tv_usec + 500000) / 1000000;
        !           546:        wtmp[1].ut_time = ntime.tv_sec + (ntime.tv_usec + 500000) / 1000000;
        !           547:        if (wtmp[0].ut_time == wtmp[1].ut_time)
        !           548:                return;
        !           549:        if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) {
        !           550:                (void) write(f, (char *)wtmp, sizeof(wtmp));
        !           551:                (void) close(f);
        !           552:        }
        !           553: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.