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

unix.superglobalmegacorp.com

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