Annotation of 43BSDTahoe/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.
                      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.