Annotation of 43BSD/etc/timed/master.c, revision 1.1.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.